SQLAlchemy + FasyAPI = EmpyDatabase Table Without Tables - python-3.x

Im trying to create a new DataBase with SQLAlchemy using FastAPI but when i run the server i get a empty DB file without tables.
database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./fastapi-test.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
models.py
from db.database import Base
from sqlalchemy import Column, Integer, String
class DbUser(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, index=True)
username = Column(String)
email = Column(String)
password = Column(String)
main.py
from fastapi import FastAPI
from routers import blogs_get, blog_post
from db import models
from db.database import engine
app = FastAPI()
app.include_router(blogs_get.router)
app.include_router(blog_post.router)
#app.get('/')
def index():
return 'Hello World'
models.Base.metadata.create_all(engine)
I already try to rewrite all the model. but i think i have an issue importing the Base component from Database

Related

SQLAlchemy : NoForeignKeysError: Could not determine join condition

I'm writing a site for a Flask,and I made a mistake when I want to connect migrations, shows this error
sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship Users.roles - there are no foreign keys
linking these tables via secondary table 'сайт.role_users'. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or
specify 'primaryjoin' and 'secondaryjoin' expressions.
Here is my code:
from flask import Flask, render_template, request, flash, \
redirect, url_for
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flask_migrate import Migrate
from flask_security import RoleMixin
import os
css_file = 'static/css/main.css'
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///lib.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
db = SQLAlchemy(app)
manager = LoginManager(app)
migrate = Migrate(app, db)
role_users = db.Table('role_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')),
)
class Users(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
login = db.Column(db.String(75), nullable=False, unique=True)
password = db.Column(db.String(80), nullable=False)
roles = db.relationship('Roles', secondary=role_users, backref=db.backref('users',
lazy='dynamic'))
def __repr__(self):
return f'<User> -----> {self.login}'
class Roles(db.Model, RoleMixin):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), unique=True, nullable=False)
def __repr__(self):
return f'<Role> ----> {self.title}'
Although there were no such errors during the first migration
.......
Help solve this problem

InValid Pydantic Field Type POST parameters (FastApi) - Python 3.8

I am attempting to use FastApi + SqlAlchemy And am having an issue with Parameters. This is the Error my Post parameter is causing. What am i doing wrong?
ERROR MESSAGE
fastapi.exceptions.FastAPIError: Invalid args for response field! Hint: check that <class 'app.models.Post'> is a valid pydantic field type
Code
from fastapi import FastAPI, Response, HTTPException
from fastapi.params import Body, Depends
from sqlalchemy.orm import Session
from starlette import status
from . import models
from .database import engine, get_db
from .models import Post
models.Base.metadata.create_all(bind=engine)
app = FastAPI()
#app.get("/posts")
def get_posts(db: Session = Depends(get_db)):
posts = db.query(models.Post).all()
return {"data": posts}
#app.post("/posts", status_code = status.HTTP_201_CREATED)
def create_posts(post: Post, db: Session = Depends(get_db)):
new_post = models.Post(title=post.title, content=post.content, published=post.published)
# db.add(new_post)
# db.commit()
# db.refresh(new_post)
return {"data": new_post}
Post Type
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.sql.expression import text
from sqlalchemy.sql.sqltypes import TIMESTAMP
from .database import Base
class Post(Base):
__tablename__ = "postsalchemy"
id = Column(Integer, primary_key=True, nullable=False)
title = Column(String, nullable=False)
content = Column(String, nullable=False)
published = Column(Boolean, server_default='TRUE', nullable=False)
created_at = Column(TIMESTAMP(timezone=True),
nullable=False, server_default=text('now()'))
FastAPI uses Pydantic library to validate both HTTP request and HTTP response body. ( BTW Pydantic is a library that will provide you validation of data structure against a given schema )
For that purpose, you must create a Pydantic Model class that corresponds to your sqlalchemy Post class.
Please read the docs here to learn more about response model.
FYI, here is how to do with your example :
from fastapi import FastAPI, Response, HTTPException
from fastapi.params import Body, Depends
from sqlalchemy.orm import Session
from starlette import status
from . import models
from .database import engine, get_db
from .models import Post
from pydantic import BaseModel
from datetime import datetime
from typing import Dict, List
# Define your pydantic response model
class PostResponse(BaseModel):
id: int
title: str
content: str
published: bool
created_at: datetime
models.Base.metadata.create_all(bind=engine)
app = FastAPI()
# Set PostResponse as a response model in the route decorator
#app.get("/posts", response_model=Dict[str, List[PostResponse]])
def get_posts(db: Session = Depends(get_db)):
posts = db.query(models.Post).all()
return {"data": posts}
#app.post("/posts", status_code = status.HTTP_201_CREATED, response_model=Dict[str, PostResponse])
def create_posts(post: Post, db: Session = Depends(get_db)):
new_post = models.Post(title=post.title, content=post.content, published=post.published)
# db.add(new_post)
# db.commit()
# db.refresh(new_post)
return {"data": new_post}
EXTRA : You might be also interested in SQLModel library which is from the same author of FastAPI and is a combination between SQL Alchemy and Pydantic library and basically allow you to avoid duplication (and declare your model only once)

AttributeError: 'set' object has no attribute '_sa_instance_state' - SQLAlchemy

Im trying to input multiple requests to one session, the idea is to log http traffic with mitmproxy but im still constructing the database, im sure there is something bad in my models but i cannot find what
The idea is to Store multiple requests in one session, accesing easily to each requests response if needed.
db.py
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
schema_name = 'Traffic'
engine = create_engine('postgresql://xxx:xxx#localhost:5432/xxx')
if not engine.dialect.has_schema(engine, schema_name):
engine.execute(sqlalchemy.schema.CreateSchema(schema_name))
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()
Request.py
from sqlalchemy.orm import relationship
from entities.utils import db
from entities.utils.utils import _repr
from sqlalchemy import Column, String, JSON, INTEGER, ForeignKey, Integer, DateTime
class RequestModel(db.Base):
__tablename__ = 'requests'
id = Column(Integer, primary_key=True,autoincrement=True)
headers = Column(JSON,nullable=False)
method = Column(String,nullable=False)
size = Column(INTEGER,nullable=False)
timestamp_end = Column(DateTime,nullable=False)
timestamp_start = Column(DateTime,nullable=False)
status_code = Column(INTEGER,nullable=False)
body = Column(JSON,nullable=True)
url = Column(String,nullable=False)
response_id = Column(INTEGER,ForeignKey('responses.id'))
def __init__(self,method,status_code,url):
self.method = method
self.status_code = status_code
self.url = url
Session.py
from sqlalchemy.orm import relationship
from entities.utils import db
from entities.utils import utils
from sqlalchemy import Column, String, Integer, ForeignKey
class SessionModel(db.Base):
__tablename__ = 'sessions'
id = Column(Integer, primary_key=True,autoincrement=True)
server = Column(String, nullable=False)
world = Column(String,nullable=False)
user = Column(String,nullable=False)
version = Column(String,nullable=False)
requests_id = Column(Integer, ForeignKey('requests.id'))
requests = relationship('RequestModel')
def __init__(self,server,world,user,version):
self.server = server
self.world = world
self.user = user
self.version = version
def __repr__(self):
return self._repr(id=self.id,server=self.server,
world=self.world,user=self.user,version=self.version)
Response.py
from sqlalchemy.orm import relationship, declarative_base
from entities.utils import db
from entities.utils.utils import _repr
from sqlalchemy import Column, JSON, INTEGER, ForeignKey, Integer
class ResponseModel(db.Base):
__tablename__ = 'responses'
id = Column(Integer, primary_key=True, autoincrement=True)
headers = Column(JSON, nullable=False)
status_code = Column(INTEGER, nullable=False)
body = Column(JSON, nullable=True)
def __init__(self, headers, status_code, body):
self.headers = headers
self.status_code = status_code
self.body = body
def __repr__(self):
return self._repr(id=self.id, status=self.status_code)
Input.py
import json
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.ext.declarative import declarative_base
import datetime
from entities.models.Request import RequestModel
from entities.models.Response import ResponseModel
from entities.models.Session import SessionModel
engine = create_engine('postgresql://XXX:XXX#localhost:5423/XXXX')
Base = declarative_base()
# create session and add objects
with Session(engine) as session:
response_object = ResponseModel(body={'22':'22'},status_code=402,headers={'test':'test'})
session.add(response_object)
session.commit()
object_1 = RequestModel('POST', 402, 'www.intersecting.com/url?=parameter1&key')
object_1.headers = {'test':'19'}
object_1.body = {'test':'19'}
object_1.size = 512
object_1.timestamp_start = datetime.datetime.now()
object_1.timestamp_end =datetime.datetime.now()
object_2 = object_1
session.add(object_1)
session.commit()
session_object = SessionModel('www.test.com','test62','admin','3.12.13')
print(session_object)
session_object.requests = {object_2,object_1}
session.add(session_object)
session.commit()
But im not able to store 2 requests in one session i get this error.
Traceback (most recent call last):
File "C:/Users/qwert/PycharmProjects/Tribalwars/entities/utils/examples/input.py", line 35, in <module>
session.add(session_object)
File "C:\Users\qwert\AppData\Local\Programs\Python\Python38\lib\site-packages\sqlalchemy\orm\session.py", line 2573, in add
self._save_or_update_state(state)
File "C:\Users\qwert\AppData\Local\Programs\Python\Python38\lib\site-packages\sqlalchemy\orm\session.py", line 2589, in _save_or_update_state
for o, m, st_, dct_ in mapper.cascade_iterator(
File "C:\Users\qwert\AppData\Local\Programs\Python\Python38\lib\site-packages\sqlalchemy\orm\mapper.py", line 3166, in cascade_iterator
queue = deque(
File "C:\Users\qwert\AppData\Local\Programs\Python\Python38\lib\site-packages\sqlalchemy\orm\relationships.py", line 1982, in cascade_iterator
tuples = state.manager[self.key].impl.get_all_pending(state, dict_)
File "C:\Users\qwert\AppData\Local\Programs\Python\Python38\lib\site-packages\sqlalchemy\orm\attributes.py", line 1169, in get_all_pending
ret = [(instance_state(current), current)]
AttributeError: 'set' object has no attribute '_sa_instance_state'

Flask-migrate No changes in schema detected

I am trying to understand how flask and sqlalchemy works.Below is my app structure
init.py contains
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
import User
# Create a login manager object
login_manager = LoginManager()
app = Flask(__name__)
# Often people will also separate these into a separate config.py file
app.config['SECRET_KEY'] = 'mysecretkey'
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
model.py
from test import db
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
class User(db.Model, UserMixin):
# Create a table in the db
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
def __init__(self, email, username, password,first_name,last_name):
self.email = email
and app.py
# This is app.py, this is the main file called.
from test import app
from flask import render_template
#app.route('/')
def index():
return 'Hello World'
if __name__ == '__main__':
app.run(debug=True)
and I am using below commands to create tables
set FLASK_APP=
flask db init
flask db migrate -m
But flask migrate is not detecting table and displays below message
I am unable to figure how to resolve this issue.Could someone please highlight what I am doing wrong.Thanks
You need to import model in __init__.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
import User
# Create a login manager object
login_manager = LoginManager()
app = Flask(__name__)
# Often people will also separate these into a separate config.py file
app.config['SECRET_KEY'] = 'mysecretkey'
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
from app import model
This is because model.py depends on __init__.py

Basic Flask SQLAlchemy Context Issue

I've read many of the other posts on having models separated from the main app but I can't get it to work with just app.py (my actual app) and models.py (my database models).
If I do the following I get an app.db file with no tables:
from app import db
db.create_all()
If I do the following I get a RuntimeError: No application found. Either work inside a view function or push an application context.:
from app import db
db.create_all()
I have also looked at Introduction into Contexts page and can't work out where I put def create_app():, none of it seemed to work in my case.
Here is my app.py:
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from models import userTable
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
#app.route('/', methods=['GET', 'POST'])
def home():
return "home"
if __name__ == '__main__':
app.run(debug=True)
Here is my models.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class userTable(db.Model):
__tablename__ = "userTable"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
Perhaps you could try the following:
app.py
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
import models
from models import initialize_db
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
initialize_db(app)
#app.route('/', methods=['GET', 'POST'])
def home():
return "home"
if __name__ == '__main__':
app.run(debug=True)
models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def initialize_db(app):
app.app_context().push()
db.init_app(app)
db.create_all()
class userTable(db.Model):
__tablename__ = "userTable"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
The key is creating a database initialization function within models.py which takes the application instance as a parameter. This function only creates the database tables once it has its application instance. This will allow you to import the models module initially without an application instance and still have a modular design.

Resources