I has a FastAPI project where I have main.py, endpoints.py (with endpoint functions) and users_db.py where I have list of dictionaries. Every dictionary save users data. It just pet project to understand web application. An now I want to create database. I chose SQL. Can somebody explaine or give a link where is described how to do that?! Or is it very hard?!
it's very simple.
first you need install sqlalchemy
pip install SQLAlchemy
then create database.py file and paste the following code to that.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
then create models.py file and write some database models you need.
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from .database import Base
class User(Base):
__tablename__ = "users" # this is table name
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
is_active = Column(Boolean, default=True)
Read the documentation for more information.
documentation
Related
I want to create an api for login authentication. I have used the below method to create the table, but I don't want to create a new table but instead use an existing table.
main.py
from fastapi import FastAPI
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from database import Base, engine, SessionLocal
class User( Base ):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
is_active = Column(Boolean, default=True)
items = relationship("Item", back_populates="owner")
Base.metadata.create_all(bind=engine)
database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
SQLALCHEMY_DB_URL = "mysql://root:mumbaicity#localhost:3306/ryr"
engine = create_engine(SQLALCHEMY_DB_URL)
SessionLocal = sessionmaker(autocommit=False, bind=engine)
Base = declarative_base()
conn = engine.connect()
this is the table I want to use: (employee):
enter image description here
You can simply not run Base.metadata.create_all(bind=engine) and define a class for the table you want.
If you have many tables and want to automatically generate model classes, look into sqlacodegen.
I created declarative table.
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String
from sqlalchemy.dialects.postgresql import UUID
import uuid
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=True)
name = Column(String)
I need to filter data. In the Flask-SQLAlchemy, I do
name = 'foo'
User.query.filter_by(name=name).first()
But if I use SQLAlchemy without Flask, then I get the error:
type object 'User' has no attribute 'query'
The only way that works for me is to filter the data through the session.
engine = create_engine('DATABASE_URL')
Session = sessionmaker(bind=engine)
session = Session()
name = 'foo'
user = session.query(User).filter_by(name=name).first()
session.close()
The Model.query... idiom is not a default part of the SQLAlchemy ORM; it's a customisation provided by Flask-SQLAlchemy. It is not available in base SQLAlchemy, and that is why you get the error message.
Why? ...because query object is not set on Base/model object automatically.
Solution is to add this line to your base:
Base.query = SessionLocal.query_property()
(where SessionLocal is instance of scoped_session)
This will make query available on all of your models and should solve your issue.However, mypy and pylint will still be complaining about this (that's how I found this question).
I have an app I am using where all of my models and my session are stored within a single models.py file:
import datetime
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy import Column, Date, Integer, String, DateTime, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
engine = create_engine('sqlite:///bidbot.db', echo=True)
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()
class AgentLog(Base):
__tablename__ = 'agentlog'
id = Column(Integer, primary_key=True)
created_at = Column(DateTime,default=datetime.datetime.utcnow)
ingroups = Column(String)
total_calls = Column(Integer)
calls_waiting = Column(Integer)
agents_logged_in = Column(Integer)
agents_in_calls = Column(Integer)
agents_waiting = Column(Integer)
agents_paused = Column(Integer)
agents_in_dispo = Column(Integer)
agents_in_dial = Column(Integer)
def create_new():
session.add(AgentLog())
session.commit()
As you can see, I have a custom create_new method which uses the session to create a new object.
If I run this models.py file on its own:
python -i models.py
Then I can call the AgentLog.create_new() function and it creates a new record.
However, I am importing models.py into my higher level package:
from models.py import *
And when I run the same function on the model:
AgentLog.create_new()
I now get a no such table exists error... Which is confusing because I believe the method should have access to the exact same session object.
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: agentlog
Figured it out! When I imported the package, it was defining the engine with the relative path based on the importing directory, not the models.py module.
I needed to update the path to use relative directory based on the models.py file:
import os
DATABASE_DIR = os.path.dirname(os.path.abspath(__file__)) + '\\bidbot.db'
engine = create_engine('sqlite:///'+DATABASE_DIR, echo=True)
I have a User class:
class User(db.Model, UserMixin):
"""
ORM Class: An object that represents a user
"""
__tablename__ = "Users"
id = db.Column('id', db.Integer, primary_key=True)
email = db.Column('email', db.String(128), unique=True)
passwordhash = db.Column('passwordhash', db.String(128))
def __init__(self, email, password):
self.email = email
self.passwordhash = generate_password_hash(password)
logging.info("creating user with email and pw:" + email + " " + password)
And when I create a new user:
newuser = User(email="test#email.com", password="hunter2")
db.session.add(newuser)
I get a KeyError: 140736669950912
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/util/_collections.py", line 988, in __call__
return self.registry[key]
KeyError: 140736669950912
Where is this number coming from? I am also getting another error during the handling of that KeyError which is a RuntimeError: application not registered on db instance and no applicationbound to current context
As recommended in their current documentation,
instead of manually creating an instance of SqlAlchemy() and saving it to db, try inheriting from sqlalchemy.ext.declarative.Base, like so:
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine(DATABASE_URI, echo=False)
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
# the following should be moved to your models.py
from sqlalchemy import Column, Integer, String
class User(Base):
"""ORM Class: An object that represents a user
"""
__tablename__ = "Users"
id = Column(Integer)
email = Column(String(128), primary_key=True)
passwordhash = Column(String(128), unique=True)
Checking whether your migrations are upto date might also help. When I faced this problem, it got fixed after I removed the existing and re-ran migrations:
python manage.py db migrate
python manage.py db ugrade
When I use sqlacodegen to create models.py I can't use User.query, getting the warning "[AttributeError: type object 'User' has no attribute 'query']".
I think db.query is a very usable attribute, it's used in SQLAlchemy():
db = SQLAlchemy()
But I need to use sqlacodegen to create models for existing table in our system. Creation code below:
models.py
# coding: utf-8
from sqlalchemy import Column, Date, Float, Integer, String, Table, text
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
metadata = Base.metadata
class User(Base):
__tablename__ = u'users'
id = Column(Integer, primary_key=True)
email = Column(String(64))
username = Column(String(64))
role_id = Column(Integer)
password_hash = Column(String(128))
Now I import models.py:
from models import *
#main.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.name.data).first()
...
When I run this, the warning given is:
AttributeError: type object 'User' has no attribute 'query'
I want to know how I can trans [class User(Base)] to a type like [class User(db.Model)] so it can use .query attribute? Or is there some other usable method to do that with [class User(Base) ]type?
It sounds like you're used to using Flask-SQLAlchemy, which includes the secret sauce to allow the functionality you mention.
The Flask Docs on SQLAlchemy indicate how to get that same functionality:
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
It'll enable the shorthand of User.query.... that you expect. The important line is the last one. You could alternatively use the db.Model class from Flask-SQLAlchemy instead of the 'pure' SQLAlchemy Base class.