I am new using FastAPI python and I am right now just trying to GET all the appointments in the database. The models.py is autogenerated with sqlacodegen. So it is one-to-one with the database and we have connection to the database.
But the problem is that when I try to go to http://127.0.0.1:8000/appointments it gives this data:
{"detail":[{"loc":["query","self"],"msg":"field required","type":"value_error.missing"}]}
and the server gives this "GET /appointments HTTP/1.1" 422 Unprocessable Entity"
but I don't know what is wrong..
in the database the data looks like this: (dummy data)
i have uploaded all my code under here:
Models.py
# coding: utf-8
from sqlalchemy import Column, DateTime, ForeignKey, String, Table
from sqlalchemy.dialects.mysql import INTEGER
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from .database import Base
Base = declarative_base()
metadata = Base.metadata
class Customer(Base):
__tablename__ = 'Customer'
CPR = Column(INTEGER(11), primary_key=True)
Name = Column(String(45))
Email = Column(String(45))
PhoneNumber = Column(INTEGER(11))
class Producer(Base):
__tablename__ = 'Producer'
CVR = Column(INTEGER(11), primary_key=True)
Name = Column(String(45))
PhoneNumber = Column(INTEGER(11))
Adress = Column(String(45))
Supplier = relationship('Supplier', secondary='Producer_has_Supplier')
class Statistic(Base):
__tablename__ = 'Statistics'
idStatistics = Column(INTEGER(11), primary_key=True)
CustomerCount = Column(INTEGER(11))
ArtistCustomerCount = Column(INTEGER(11))
SessionCount = Column(INTEGER(11))
AppliedInkColorCount = Column(INTEGER(11))
class Supplier(Base):
__tablename__ = 'Supplier'
CVR = Column(INTEGER(11), primary_key=True)
Name = Column(String(45))
PhoneNumber = Column(String(45))
Adress = Column(String(45))
class Ink(Base):
__tablename__ = 'Ink'
BatchNumber = Column(INTEGER(11), primary_key=True, nullable=False)
Brand = Column(String(45))
ColorCode = Column(String(15))
ExperationDate = Column(DateTime)
Price = Column(INTEGER(11))
Producer_CVR = Column(ForeignKey('Producer.CVR'), primary_key=True, nullable=False, index=True)
Producer = relationship('Producer')
Tattoo = relationship('Tattoo', secondary='Tattoo_has_Ink')
t_Producer_has_Supplier = Table(
'Producer_has_Supplier', metadata,
Column('Producer_CVR', ForeignKey('Producer.CVR'), primary_key=True, nullable=False, index=True),
Column('Supplier_CVR', ForeignKey('Supplier.CVR'), primary_key=True, nullable=False, index=True)
)
class Tattooparlor(Base):
__tablename__ = 'Tattooparlor'
CVR = Column(INTEGER(11), primary_key=True, nullable=False)
Name = Column(String(75))
Adress = Column(String(45))
PhoneNumber = Column(INTEGER(11))
Email = Column(String(45))
Statistics_idStatistics = Column(ForeignKey('Statistics.idStatistics'), primary_key=True, nullable=False, index=True)
Supplier_CVR = Column(ForeignKey('Supplier.CVR'), primary_key=True, nullable=False, index=True)
Statistic = relationship('Statistic')
Supplier = relationship('Supplier')
class Artist(Base):
__tablename__ = 'Artist'
CPR = Column(INTEGER(11), primary_key=True)
Name = Column(String(45))
PhoneNumber = Column(INTEGER(11))
Email = Column(String(45))
Price = Column(INTEGER(11))
Tattooparlor_CVR = Column(ForeignKey('Tattooparlor.CVR'), nullable=False, index=True)
Tattooparlor = relationship('Tattooparlor')
t_Parlor_has_Ink = Table(
'Parlor_has_Ink', metadata,
Column('Ink_batchnumber', ForeignKey('Ink.BatchNumber'), index=True),
Column('Parlor_storageID', ForeignKey('Tattooparlor.CVR'), index=True),
Column('Quantity', INTEGER(11))
)
class Appointment(Base):
__tablename__ = 'Appointment'
id = Column(INTEGER(11), primary_key=True, nullable=False)
DateTime = Column(DateTime)
SessionLenght = Column(INTEGER(11))
Customer_CPR = Column(ForeignKey('Customer.CPR'), primary_key=True, nullable=False, index=True)
Tattooparlor_CVR = Column(ForeignKey('Tattooparlor.CVR'), primary_key=True, nullable=False, index=True)
Artist_CPR = Column(ForeignKey('Artist.CPR'), nullable=False, index=True)
Artist = relationship('Artist')
Customer = relationship('Customer')
Tattooparlor = relationship('Tattooparlor')
class Tattoo(Base):
__tablename__ = 'Tattoo'
idTattoo = Column(INTEGER(11), primary_key=True, nullable=False)
Description = Column(String(200))
PlacementOnBody = Column(String(45))
Appointment_idAppointment = Column(ForeignKey('Appointment.idAppointment'), primary_key=True, nullable=False, index=True)
Appointment = relationship('Appointment')
t_Tattoo_has_Ink = Table(
'Tattoo_has_Ink', metadata,
Column('Tattoo_idTattoo', ForeignKey('Tattoo.idTattoo'), primary_key=True, nullable=False, index=True),
Column('Ink_BatchNumber', ForeignKey('Ink.BatchNumber'), primary_key=True, nullable=False, index=True)
)
Schemas.py
from typing import List
from sqlalchemy.orm import Session
from .models import Appointment
from .schemas import AppointmentBase
# Function to get list of car info
def get_all_apointments(session: Session) -> List[Appointment]:
print(List[Appointment])
return session.query(Appointment).all()
crud.py
from typing import List, Optional
from pydantic import BaseModel
import datetime
# TO support creation and update APIs
class AppointmentBase(BaseModel):
DateTime = str(datetime)
SessionLenght = int
# TO support list and get APIs
class Appointment(AppointmentBase):
Appointment_id = int
Customer_CPR = int
Tattooparlor_CVR =int
Artist_CPR = int
class Config:
orm_mode = True
arbitrary_types_allowed = True
# To support list API
class PaginatedAppointmentInfo(BaseModel):
data: List[Appointment] = []
class Config:
orm_mode = True
arbitrary_types_allowed = True
main.py
from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session
from pydantic import BaseModel
import uvicorn
from . import models
from .database import SessionLocal, engine
from .schemas import Appointment, AppointmentBase, PaginatedAppointmentInfo
from .crud import get_all_apointments
# Initialize the app
app = FastAPI()
models.Base.metadata.create_all(bind=engine)
app = FastAPI()
# Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# API to get the list of car info
#app.get("/appointments", response_model=PaginatedAppointmentInfo)
def list_apointments(self):
apointments_list = get_all_apointments(self.session)
response = {"data": apointments_list}
return response
# GET operation at route '/'
#app.get('/')
def root_api():
return {"message": "Welcome to Balasundar's Technical Blog"}
The error message is telling you that you have defined a required query argument named self that isn't being submitted:
{"detail":[{"loc":["query","self"],"msg":"field required"
^ ^
type name
If you look at the function you're calling, you'll see that you have a definition that mentions that specific name:
# API to get the list of car info
#app.get("/appointments", response_model=PaginatedAppointmentInfo)
def list_apointments(self):
^
Since there is no implicit first argument for regular functions (only for methods inside a class), FastAPI expects a self argument to be supplied to the function. Since you're not including that - I'm guessing you have extracted this from a class, since you're also using self.session further down - FastAPI gives an error.
As you have defined a get_db dependency to get the session, you should probably use that instead (since self outside of a class context doesn't have any particular meaning):
# API to get the list of car info
#app.get("/appointments", response_model=PaginatedAppointmentInfo)
def list_apointments(session = Depends(get_db)):
apointments_list = get_all_apointments(session)
response = {"data": apointments_list}
return response
There is no longer any required arguments for the function - the session gets retrieved from get_db and there are no other arguments to the function.
Related
I am trying to use ORM with SQLAlchemy in Python. My current solution fails and throws an exception right in the moment the ORM is first used. I receive the following exception:
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Event->event, expression 'Tag' failed to locate a name ('Tag'). If this is a class name, consider adding this relationship() to the <class 'backend.source.database.event.Event'> class after both dependent classes have been defined.
My classes are defined like in the offical SQLAlchemy-Documentation (https://docs.sqlalchemy.org/en/14/orm/basic_relationships.html#many-to-many), which is why I am kinda confused about that error.
association = Table('event_to_tag', declarative_base().metadata,
Column('event_id', Integer, ForeignKey('event.id'), primary_key=True),
Column('tag_id', Integer, ForeignKey('tag.id'), primary_key=True))
class Event(declarative_base()):
__tablename__ = "event"
id = Column(Integer, primary_key=True)
title = Column(String(255))
location = Column(String(255))
organizer_id = Column(Integer, ForeignKey(Organizer.id))
start = Column(DateTime)
end = Column(DateTime)
lang = Column(String(255))
costs = Column(DECIMAL)
registration = Column(TINYINT)
url = Column(String(255))
description = Column(Text)
tags = relationship("Tag", secondary=association, back_populates="events")
class Tag(declarative_base()):
__tablename__ = "tag"
id = Column(Integer, primary_key=True)
name = Column(String(255))
events = relationship("Event", secondary=association, back_populates="tags")
Thank you, greetings
I think you need to define a Base = declarative_base(), need to use in your models and associations.
from sqlalchemy import Column, Integer, ForeignKey, String, DECIMAL, Text, DateTime, Table, create_engine
from sqlalchemy.dialects.mssql import TINYINT
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import declarative_base, relationship, scoped_session, sessionmaker
Base = declarative_base()
association = Table('event_to_tag',
Base.metadata,
Column('event_id', Integer, ForeignKey('events.id'), primary_key=True),
Column('tag_id', Integer, ForeignKey('tags.id'), primary_key=True))
class Event(Base):
__tablename__ = "events"
id = Column(Integer, primary_key=True)
title = Column(String(255))
location = Column(String(255))
# organizer_id = Column(Integer, ForeignKey(Organizer.id))
start = Column(DateTime)
end = Column(DateTime)
lang = Column(String(255))
costs = Column(DECIMAL)
registration = Column(UUID)
url = Column(String(255))
description = Column(Text)
tags = relationship("Tag", secondary=association, back_populates="events")
class Tag(Base):
__tablename__ = "tags"
id = Column(Integer, primary_key=True)
name = Column(String(255))
events = relationship("Event", secondary=association, back_populates="tags")
class CreateEngine:
def __init__(self):
self.connection_string = "postgresql+psycopg2://<user_name>:<password>#127.0.0.1/<table_name>"
self.engine = create_engine(self.connection_string)
def create_table(self):
return Base.metadata.create_all(self.engine)
def create_session(self):
session_factory = sessionmaker(bind=self.engine)
Session = scoped_session(session_factory)
with Session() as session:
pass
if __name__ == "__main__":
CreateEngine().create_table()
I am trying to create an API in Python that uses a Postgresql database. I am attempting a simple endpoint to pull to check to see if the database can connect and pull data. I am probably missing something simple and need someone to point it out. Below is my main.py file
import psycopg2
import model
import os
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
uname = os.environ['uname']
pas = os.environ['pas']
url = os.environ['url']
port = os.environ['port']
dbase = os.environ['dbase']
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://' + uname + ':' + pas + '#' + url + ':' + port + '/' + dbase
db = SQLAlchemy(app)
#app.route('/test')
def test():
tst = model.Doc.query.filter_by(doc_num=1).first()
return jsonify(tst)
if __name__ == '__main__':
app.run()
I also have a model.py file where my database is modeled out.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String, Date, ForeignKey
from flask_marshmallow import Marshmallow
app = Flask(__name__)
db = SQLAlchemy(app)
ma = Marshmallow(app)
class Aud(db.Model):
__tablename__ = 'aud'
__table_args__ = {'schema': 'cirsx'}
aud_num = Column(Integer, primary_key=True)
aud_name = Column(String, nullable=False, unique=True)
aud_desc = Column(String)
class AudSchema(ma.Schema):
class Meta:
fields = ('aud_num', 'aud_name', 'aud_desc')
class DocTyp(db.Model):
__tablename__ = 'doctyp'
__table_args__ = {'schema': 'cirsx'}
doctyp_num = Column(Integer, primary_key=True)
doctyp_name = Column(String, nullable=False, unique=True)
doctyp_desc = Column(String)
class DocTypSchema(ma.Schema):
class Meta:
fields = ('doctyp_num', 'doctyp_name', 'doctyp_desc')
class Doc(db.Model):
__tablename__ = 'doc'
__table_args__ = {'schema': 'cirsx'}
doc_num = Column(Integer, primary_key=True)
doctyp_num = Column(Integer, ForeignKey('doctyp_num'))
aud_num = Column(Integer, ForeignKey('aud_num'))
doc_path = Column(String, nullable=False)
title = Column(String, nullable=False)
author = Column(String)
keywords = Column(String)
pub_dt = Column(Date)
doc_abs = Column(String)
doc_txt = Column(String)
class DocSchema(ma.Schema):
class Meta:
fields = ('doc_num',
'doctyp_num',
'aud_num',
'doc_path',
'title',
'author',
'keywords',
'pub_dt',
'doc_abs',
'doc_txt')
aud_schema = AudSchema()
aud_schemas = AudSchema(many=True)
doctyp_schema = DocTypSchema()
doctyp_schemas = DocTypSchema(many=True)
doc_schema = DocSchema()
doc_schemas = DocSchema(many=True)
if __name__ == '__main__':
app.run()
Is there something that I am missing to why I am getting this error?
I have postgres db with some data, i can do everything i want until i add relation to Employee and EmployeeExperience, then a get an error lok like:
InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class EmployeeExperience->employee_experience'. Original exception was: Mapper 'mapped class Employee->employee' has no property 'employee_experience'
I read a lot of tutorials and don't unerstand what i did wrong, any solution doesn't work for me, pls help, here is my code.
import psycopg2
import datetime
# <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
from flask import Flask
from flask_bcrypt import Bcrypt
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "postgres://postgres:postgres#localhost:5433/db_name"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy()
db.init_app(app)
flask_bcrypt = Bcrypt()
flask_bcrypt.init_app(app)
app.app_context().push()
# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< models
class Employee(db.Model):
__tablename__ = "employee"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
surname = db.Column(db.String(200))
first_name = db.Column(db.String(200))
birth_date = db.Column(db.Date)
email = db.Column(db.String(300), unique=True)
city = db.Column(db.String(200))
latitude = db.Column(db.Float)
longitude = db.Column(db.Float)
male = db.Column(db.Integer)
registered_on = db.Column(db.DateTime)
active = db.Column(db.Integer)
_password = db.Column(db.String(400))
employee_experience = db.relationship("EmployeeExperience", back_populates="employee")
class EmployeeExperience(db.Model):
__tablename__ = "employee_experience"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
position = db.Column(db.String(300))
company = db.Column(db.String(200))
city = db.Column(db.String(200))
description = db.Column(db.Text)
desc_raw = db.Column(db.Text)
employee_id = db.Column(db.Integer, db.ForeignKey('employee.id'))
employee = db.relationship("Employee", back_populates="employee_experience")
# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
emp = Employee.query.first()
'mapped class Employee->employee' has no property 'employee_experience'
The error cause is clearly stated. You have not defined the employe_experience attribute yet on your Employee model
I have several classes:
import uuid
from app import db, create_app
from sqlalchemy.sql import func
from sqlalchemy.dialects.postgresql import UUID, ARRAY, JSONB
class Ticket(db.Model):
__tablename__ = 'tickets'
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
time = db.Column(db.DateTime, server_default=func.now(), index=True)
proposed_names = db.Column(ARRAY(db.String))
measurements = db.relationship('TempMeasurement', back_populates='ticket')
class BaseMeasurement(object):
id = db.Column(db.Integer, primary_key=True)
#declared_attr
def type_id(self):
return db.Column(db.Integer, db.ForeignKey('optical_data_types.id'))
#declared_attr
def type(self):
return db.relationship('OpticalDataType')
#declared_attr
def operator_id(self):
return db.Column(db.Integer, db.ForeignKey('operators.id'))
#declared_attr
def operator(self):
return db.relationship('Operator')
#declared_attr
def item_id(self):
return db.Column(db.String, db.ForeignKey('items.serial'))
#declared_attr
def item(self):
return db.relationship('Item')
time = db.Column(db.DateTime, index=True)
instrument = db.Column(db.String)
instrument_sn = db.Column(db.String)
data = db.Column(JSONB)
class TempMeasurement(db.Model, BaseMeasurement):
__tablename__ = 'ticket_data'
id = db.Column(db.Integer, primary_key=True)
ticket_id = db.Column(UUID(as_uuid=True), db.ForeignKey('tickets.id'), index=True)
ticket = db.relationship('Ticket', back_populates='measurements')
original_paths = db.Column(ARRAY(db.String))
What I want/expect is that I can create a Ticket with several child TempMeasurements and commit this to the database. Something like:
app = create_app()
with app.app_context():
ticket = Ticket()
ticket.measurements = [TempMeasurement(...)]
db.session.add(ticket) # <-- error on this line
db.session.commit()
However, I get an obscure error deep in SQLAlchemy:
AttributeError: 'str' object has no attribute '_sa_instance_state'
with a full trace here.
I thought that it might be because the UUID ticket_id column has as_uuid, so I made it simply UUID (implicitly a str), but this did not solve my issue.
The error is too deep in SQLAlchemy for me to understand -- can anyone help?
I am trying to do a relationship() with an OUTER JOIN so that it joins the second table if there is something to join it with. I am currently stuck on how to do this though, I cannot seem to figure out the right combination of options(), relationship() and outerjoin().
I have the following tables and I am trying to join AppLike to Application if a row exists with the Application ID AND the artistID (which is provided by the function)
Happy to provide any additional information, I already have one of my joins working as you can see below, but there will always be a row to match for that one.
from sqlalchemy import Column
from . import Base
from . import DBSession
from sqlalchemy.dialects.mysql import (
INTEGER,
VARCHAR,
TEXT,
TINYINT,
)
from sqlalchemy.sql import and_
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, joinedload
import time
# 0 = new
# 1 = Denied
# 2 = Accepted
def getNewApplications(artistID):
query = DBSession.query(Application).\
options(joinedload('pieces')).\
options(joinedload('vote')).\
filter(AppLike.artist_id==artistID).\
filter(Application.approved==0)
#join(AppPiece, Application.app_id==AppPiece.app_id).\
#outerjoin(AppLike, and_(Application.app_id==AppLike.app_id,
# AppLike.artist_id==artistID)).\
import pdb; pdb.set_trace()
return query.all()
class Application(Base):
""" The SQLAlchemy declarative model class for a FileFavorite object. """
__tablename__ = 'applications'
__table_args__ = {
'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8'
}
app_id = Column(INTEGER(11), autoincrement=True, primary_key=True, nullable=False)
name = Column(VARCHAR(64), nullable=False)
nickname = Column(VARCHAR(64), nullable=False)
email = Column(VARCHAR(255), nullable=False)
description = Column(TEXT(), nullable=False)
profile_link = Column(VARCHAR(128), nullable=False)
location = Column(VARCHAR(64), nullable=False)
approved = Column(TINYINT(4), nullable=False)
pieces = relationship("AppPiece", lazy='joined')
vote = relationship("AppLike", lazy='joined')
def __init__(self, name, nickname, email, desc, profileLink,
location, approved):
self.name = name
self.nickname = nickname
self.email = email
self.description = desc
self.profile_link = profileLink
self.location = location
self.approved = approved
class AppPiece(Base):
""" The SQLAlchemy declarative model class for a FileFavorite object. """
__tablename__ = 'app_pieces'
__table_args__ = {
'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8'
}
app_piece_id = Column(INTEGER(11), autoincrement=True, primary_key=True, nullable=False)
app_id = Column(INTEGER(11), ForeignKey('applications.app_id'))
link = Column(VARCHAR(128), nullable=False)
def __init__(self, appID, link):
self.app_id = appID
self.link = link
class AppLike(Base):
""" The SQLAlchemy declarative model class for a FileFavorite object. """
__tablename__ = 'app_likes'
__table_args__ = {
'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8'
}
app_id = Column(INTEGER(11), ForeignKey('applications.app_id'))
artist_id = Column(INTEGER(11), primary_key=True, nullable=False)
vote = Column(TINYINT(4), nullable=False)
def __init__(self, appID, artistID, vote):
self.app_id = appID
self.artist_id = artistID
self.vote = vote
You definitely don't need options(joinedload('pieces')), it is already defined in your models (lazy='joined'). The join condition is the tricky part here and needs to be done using subquery, since we want to filter there as well. So, the final query should look something like this:
# We do the filtering on AppLike in the subquery and later join
# Application to it.
applike_subq = DBSession.query(AppLike).\
filter(AppLike.artist_id == artistID).subquery()
query = DBSession.query(Application).\
outerjoin(applike_subq, Application.vote).\
filter(Application.approved == 0).all()