This is how I setup my database for an application (in Flask):
from sqlalchemy.engine import create_engine
from sqlalchemy.orm import scoped_session, create_session
from sqlalchemy.ext.declarative import declarative_base
engine = None
db_session = scoped_session(lambda: create_session(bind=engine,
autoflush=False, autocommit=False, expire_on_commit=True))
Base = declarative_base()
Base.query = db_session.query_property()
def init_engine(uri, **kwargs):
global engine
engine = create_engine(uri, **kwargs)
Base.metadata.create_all(bind=engine)
return engine
If I connect to a file database that has had tables created already, everything works fine, but using sqlite:///:memory: as a target database gives me:
OperationalError: (OperationalError) no such table: users u'DELETE FROM users' ()
when querying like so for ex.:
UsersTable.query.delete()
db_session.commit()
I am accessing this code from a unit test. What is the problem?
Thanks
Edit:
Working setup of the application:
app = Flask(__name__)
app.config.from_object(__name__)
app.secret_key = 'XXX'
# presenters
from presenters.users import users
# register modules (presenters)
app.register_module(users)
# initialize the database
init_engine(db)
The code you posted doesn't contain any table/class declaration. Are you sure that the declaration is done before init_engine() is called?
Related
If I have an init.py file which looks as such:
from sqlalchemy import create_engine
import os
from sqlalchemy.orm import sessionmaker, scoped_session
from testserver.database.models.Base import Base
from sqlalchemy.ext.declarative import declarative_base
from flask_migrate import Migrate
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
def set_db_connection():
connection_string = 'sqlite:///' + os.path.join(BASE_DIR, 'testserver.db')
return connection_string
engine = create_engine(set_db_connection(), connect_args={'check_same_thread': False})
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# Set the custom base class
Base = declarative_base(cls=Base)
def init_app(app):
Base.metadata.create_all(engine)
Base.metadata.bind = engine
Session.configure(bind=engine)
app.session = scoped_session(Session)
# Export session for use in other classes
db_session = Session()
If I am to make an update to my existing models. Can I use the flask_migrate package to successfully run a migration? And if so how?
Author of Flask-Migrate here. Flask-Migrate needs Flask-SQLAlchemy or Alchemical (a still somewhat experimental package I built that uses the newer query functionality in SQLAlchemy 1.4).
If you use plain SQLAlchemy, then work with Alembic directly.
I have a simple function in Fast API app that gets called by a cron, something like this (note that this is not a get or post Fast API method but a simple function):
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
where get_db is:
from database import SessionLocal
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
And database.py is:
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "://url-to-db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
Since crud method takes db (object of SessionLocal yielded by get_db) as a param, how do I use it as a dependency injection with my function just like we use in GET or POST as shown in code read_user method above.
I've been building a flask app and using flask-sqlalchemy and flask-migrate.
Lately I decided to replace the extension with plain sqlalchemy and alembic and I started to think what's the best place to store the db session object (sqla).
Right now I have the following:
Base = declarative_base()
def init_db_session(app, expire_on_commit=True):
"""
Initialize the database
"""
engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'], convert_unicode=True)
db_session = scoped_session(
sessionmaker(autocommit=False, autoflush=False, expire_on_commit=expire_on_commit, bind=engine)
)
Base.query = db_session.query_property()
return db_session
def init_app(app):
"""
Flask app initialization and bootstrap
"""
init_logging(app)
app.celery = init_celery(app)
app.db_session = init_db_session(app)
but given some docs and examples online I'm wondering if using flask global g is any better
They both belong to the same context, I read about that in the docs and in the code but still can't get my head around the practical differences and the potential drawbacks of having it in the current_app compared to g
The flask documentation has a recommendation to declare the session in the module scope. This is also how I use it in my own code.
Base = declarative_base()
engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'], convert_unicode=True)
db_session = scoped_session(
sessionmaker(
autocommit=False,
autoflush=False,
expire_on_commit=expire_on_commit,
bind=engine
)
)
Base.query = db_session.query_property()
def init_db():
""" not much to do here if migrations are handled else where. """
pass
def init_app(app):
"""
Flask app initialization and bootstrap
"""
init_logging(app)
app.celery = init_celery(app)
app.db_session = init_db_session(app)
The lines below declare the engine and session objects.
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
URL = 'mysql://root:pass#12.34.56.78/mydb'
engine = create_engine(URL, echo=False)
session = scoped_session(sessionmaker())
session.remove()
session.configure(bind=engine, autoflush=False, expire_on_commit=False)
I would like to know how engine and session objects could be used to check if they are able to connect to the database with URL, database name and credentials provided.
Everywhere I need to query the database in my application I import the Session from this file.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
db_name = 'analytics'
db_url = 'postgresql+psycopg2://**:**#localhost:5432/{0}'.format(db_name)
Engine = create_engine(db_url, echo=False)
SessionMaker = sessionmaker(bind=Engine, autoflush=False)
Session = scoped_session(SessionMaker)
Base = declarative_base()
I'm writing some unit tests and need to mock the Session object so that whenever it is imported in my app, it connects to the unittest database rather than the analytics database.
class FacebookTest(unittest.TestCase):
#classmethod
def setUpClass(self):
"""
create unittest database and insert Premier League 2015-2016 season
"""
con = connect(user='**', host='localhost', password='**', database='postgres')
con.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
cur = con.cursor()
cur.execute('DROP DATABASE IF EXISTS unittest')
cur.execute('CREATE DATABASE unittest')
cur.close()
con.close()
Engine = create_engine('postgresql+psycopg2://**:**#localhost:5432/unittest')
Base.metadata.create_all(Engine)
Session.connection = Engine.connect()
Set your mock database on a different port, for example 5433 and change the port depending on which DB you want to connect to.
You can do like this. Let's say you have a db.py where you initiate your sessions and import them all over. Modify it like this (ignore reference to configurator, that's my internal module):
import psycopg2
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import configurator
Base = declarative_base()
def connect():
cfg = configurator.Configurator("database")
return psycopg2.connect(
user=cfg.user, host=cfg.host, dbname=cfg.db, port=cfg.port, password=cfg.pwd
)
def connect_test():
conn_string = (
"host='localhost' user='postgres' password='yourPassword' port='5433'"
)
return psycopg2.connect(conn_string)
def Session(database='dev'):
if database == 'dev':
engine = create_engine("postgresql://", creator=connect)
elif database == 'test':
engine = create_engine("postgresql://", creator=connect_test)
Session = sessionmaker(bind=engine)
return Session()
UPDATE: Important correction - added brackets in return session(), sorry about that.
UPDATE2: Changed code after explicit testing.