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.
Related
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
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'm coding an application connected with a PostgreSQL database and sqlalchemy as the ORM.
I have two classes in the simplified schema (camera and room) that I can use but without any relationship.
So for example if I select all the room I will not be able to list their cameras.
The error:
sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class Room->room'. Original exception was: When initializing mapper mapped class Room->room, expression 'Camera' failed to locate a name ('Camera'). If this is a class name, consider adding this relationship() to the <class 'models.room.Room'> class after both dependent classes have been defined.
# room.py
from sqlalchemy import Integer, Column, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Room(Base):
__tablename__ = 'room'
id_room = Column(Integer, primary_key=True)
cameras = relationship("Camera", back_populates="room")
# camera.py
from sqlalchemy import Integer, Column, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Camera(Base):
__tablename__ = 'camera'
id_camera = Column(Integer, primary_key=True)
id_room = Column(Integer, ForeignKey('room.id_room'))
room = relationship("Room", back_populates="cameras")
Just define both the classes in a single models.py file -
# models.py
from sqlalchemy import Integer, Column, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Room(Base):
__tablename__ = 'room'
id_room = Column(Integer, primary_key=True)
cameras = relationship("Camera", back_populates="room")
class Camera(Base):
__tablename__ = 'camera'
id_camera = Column(Integer, primary_key=True)
id_room = Column(Integer, ForeignKey('room.id_room'))
room = relationship("Room", back_populates="cameras")
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)
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.