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?
Related
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.
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 am trying to make one to many relationship between these 2 tables ("users" and "planets") but am getting this error:
One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class User->users'. Original exception was: Could not determine join condition between parent/child tables on relationship User.planet - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
I have seen answers to this question but none of them worked, I don't know where is the problem?
I also want to separate the 2 models in 2 different files, how that gonna work in this case?
Thanks so much for your help.
from sqlalchemy import Column, Integer, String, FLOAT
from app import db, ma
# database models:
class User(db.Model):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
first_name = Column(String)
last_name = Column(String)
email = Column(String, unique=True)
password = Column(String)
planet = db.relationship('Planet', backref='users', lazy='dynamic')
class Planet(db.Model):
__tablename__ = 'planets'
planet_id = Column(Integer, primary_key=True)
planet_name = Column(String)
planet_type = Column(String)
home_star = Column(String)
mass = Column(FLOAT)
radius = Column(FLOAT)
distance = Column(FLOAT)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
class UserSchema(ma.Schema):
class Meta:
fields = ('id', 'first_name', 'last_name', 'email', 'password')
class PlanetSchema(ma.Schema):
class Meta:
fields = ('planet_id', 'planet_name', 'planet_type', 'home_star', 'mass', 'radius', 'distance')
#__init__.py
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
import os
from flask_marshmallow import Marshmallow
from flask_jwt_extended import JWTManager, jwt_required, create_access_token
# from flask_cors import CORS, cross_origin
db = SQLAlchemy()
ma = Marshmallow()
jwt = JWTManager()
def create_app():
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'planets.db')
app.config['JWT_SECRET_KEY']='super_secret'
# cors = CORS(app)
# app.config['CORS_HEADERS'] = 'Content-Type'
db.init_app(app)
ma.init_app(app)
jwt.init_app(app)
# jwt = JWTManager(app)
from views import planet, users
app.register_blueprint(planet.main)
app.register_blueprint(users.users)
return app
I try to deal with inheritance models and sqlAlchemy, flask and flask_sqlalchemy.
The following code is working if inline :
wf_agent.py
from app import db
class WFAgent(db.Model):
__tablename__ = 'wf_agent'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), index=True, unique=True)
agent_type = db.Column(db.String(50), nullable=False)
__mapper_args__ = {'polymorphic_on': agent_type,
'polymorphic_identity': 'wf_agent'}
__table_args__ = {'extend_existing': True}
class ApiAgent(WFAgent):
__tablename__ = 'wf_agent'
__mapper_args__ = {'polymorphic_identity': 'api_agent'}
api_key = db.Column(db.String(1024))
token = db.Column(db.String(1024))
__table_args__ = {'extend_existing': True}
populate.py
from app import db
from app.models.agent.wf_agent import WFAgent, ApiAgent
db.drop_all()
db.configure_mappers()
db.create_all()
db.session.commit()
api_agent = WFAgent(name="agent 1")
db.session.add(api_agent)
api_agent = ApiAgent(name="agent 2")
db.session.add(api_agent)
db.session.commit()
But it doesnt work if I split in 2 files :
wf_agent.py
from app import db
class WFAgent(db.Model):
__tablename__ = 'wf_agent'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), index=True, unique=True)
agent_type = db.Column(db.String(50), nullable=False)
__mapper_args__ = {'polymorphic_on': agent_type,
'polymorphic_identity': 'wf_agent'}
__table_args__ = {'extend_existing': True}
api_agent.py
from app import db
from agent.wf_agent import WFAgent
class ApiAgent(WFAgent):
__tablename__ = 'wf_agent'
__mapper_args__ = {'polymorphic_identity': 'api_agent'}
api_key = db.Column(db.String(1024))
token = db.Column(db.String(1024))
__table_args__ = {'extend_existing': True}
populate.py
from app import db
from app.models.agent.wf_agent import WFAgent
from app.models.agent.api_agent import ApiAgent
db.drop_all()
db.configure_mappers()
db.create_all()
db.session.commit()
api_agent = WFAgent(name="test")
db.session.add(api_agent)
api_agent = ApiAgent(name="test")
db.session.add(api_agent)
db.session.commit()
I got the following message :
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'app.models.agent.api_agent.ApiAgent' is not mapped
Did I break Sql Alchemy ? (I'm using sqlite)
Got it ! Thanks to Univerio, I check my import
This doesn't work
from agent.wf_agent import WFAgent
but
from .wf_agent import WFAgent
is ok !
Not sure to understand why ... I need to better understand how import works :)
SQLAlchemy and for some reason when i run my create_db.py only the migration table is created.
I tried it from python terminal with from modules import db,models then running db.create_all() but it still gives the same result.
this is my models.py.
from __init__ import db
from datetime import datetime
class Batch(db.Model):
__tablename__='batch'
batch_id = db.Column(db.String, primary_key=True)
#total = db.Column(db.Integer)
success = db.Column(db.Integer)
failure = db.Column(db.Integer)
folder = db.Column(db.String(15))
email = db.Column(db.String(20))
detail = db.relationship('Conversion', backref='details',lazy='dynamic')
platform = db.relationship('Platform', backref='pub_data', lazy = 'dynamic')
def __init__(self,batch_id,success,failure,folder,email):
self.batch_id = batch_id
self.success = success
self.failure = failure
self.folder = folder
self.email = email
class Conversion(db.Model):
__tablename__ = 'conversion'
id = db.Column(db.Integer, primary_key=True)
batch_id = db.Column(db.String,db.ForeignKey('batch.batch_id'))
file_names = db.Column(db.String)
status = db.Column(db.String(6))
error = db.Column(db.Text)
res_prop = db.Column(db.Integer)
def __init__(self,batch_id,file_names,status,res_prop,error=None):
self.batch_id = batch_id
self.file_names = file_names
self.status = status
self.error = error
self.res_prop = res_prop
class Platform(db.Model):
__tablename__ = 'platform'
id= db.Column(db.Integer,primary_key=True)
batch_id = db.Column(db.String, db.ForeignKey('batch.batch_id'))
title = db.Column(db.String)
pub_date = db.Column(db.DateTime)
def __init__(self,batch_id,title):
self.batch_id = batch_id
self.title = title
self.pub_date = datetime()
And here is my create_db.py
from modules import models
from modules import db
from migrate.versioning import api
from modules.default_config import SQLALCHEMY_DATABASE_URI , SQLALCHEMY_MIGRATE_REPO
import os.path
db.create_all()
db.session.commit()
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')
api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
else:
api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, api.version(SQLALCHEMY_MIGRATE_REPO))
on changing
from __init__ import db
to
from modules import db
in models.py it worked.
when running flask application from outside package one needs to import everything from the package itself and not the individual modules.