Correct way of using session in SQLAlchemy - python

I started with sqlalchey and everything is good. But my question is: How to use session on a correct way.
For example:
I have a file like (sqlsetts.py):
from sqlalchemy import create_engine
engine = create_engine('mysql://root#127.0.0.1/test')
engine.execute("SET NAMES 'utf8'")
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine, autoflush=True, autocommit=True, expire_on_commit=True)
session = Session()
Every time I need to use a session i use following:
class test:
from sqlsettings import session
def testfunc(self):
self.session.query... bla bla
Is that correct way to include session from a file or to make a new one for each function?

Related

FastAPI Python Database connectivity

I am new to the FastAPI world, I am creating an API to fetch and post the data to the MySQL database. I followed few link on internet and developed below code
DatabaseConnection.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
sql_database_url="mysql://root:root#localhost:3306/first_db"
engine=create_engine(sql_database_url)
sessionLocal=sessionmaker(autocommit=False,bind=engine)
base=declarative_base()
MainClass.py
from fastapi import FastAPI,Query,Depends
from sqlalchemy import Column,String,Integer
from typing import Optional,List
from pydantic import BaseModel
from sqlalchemy.orm import Session
from DatabaseConnection import engine,sessionLocal,base
app=FastAPI()
class User(base):
__tablename__="users"
id=Column(Integer,primary_key=True,index=True)
name=Column(String(255),unique=True,index=True)
class UserSchema(BaseModel):
id:int
name:str
class Config:
orm_model=True
base.metadata.create_all(bind=engine)
#app.post("/create-user")
def createUser(userSchema:UserSchema):
user=User(id=userSchema.id,name=userSchema.name)
sessionLocal().add(user)
sessionLocal().commit()
return user
When i try to run this API using UVICorn i was running successful and the table also created successfully but the data that i am sending through the body is not added in the table.
The table is showing null value is added \
I have referred link
Any help will be appreciated. Thanks in advance
Thanks #anjaneyulubatta505 for help
but we need to do below changes to post data in database
#app.post("/create-user")
def createUser(userSchema:UserSchema):
user = User(id=userSchema.id, name=userSchema.name)
with Session(bind=engine) as session:
session.add(user)
session.commit()
return user
referred links
Link1
Link2 from sqlAlChemy
You are not committing the change to the database. Just change your code like below to make it work.
# ... imports and other stuff
from DatabaseConnection import sessionLocal
#app.post("/create-user")
def createUser(userSchema:UserSchema):
user = User(id=userSchema.id, name=userSchema.name)
with sessionLocal() as session:
session.add(user)
session.commit()
return user

Unable to return Postgres table names in SQL Alchemy

I've created a database, a schema and some tables in pgadmin4. In python with SQL Alchemy, I am unable to return the tables names.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine(f'postgresql+psycopg2://{pswd["Connection"]["user"]}:{pswd["Connection"]["pw"]}#{pswd["Connection"]["host"]}/{pswd["Connection"]["database"]}')
Session = sessionmaker(bind=engine)
session = Session()
session.execute('SET search_path TO schema_name;')
print(engine.table_names())
I found the "SET search_path TO schema_name" on another question, but its from 2013. I know the tables exist, I've been able to interact with psycopg2 alone. Any glaring reason as to why this may be the case?
Reading the docs, Engine.table_names() accepts the schema to look in as an argument:
print(engine.table_names("schema_name"))
Your SET is executed in a different connection from the one the engine uses.

Using Flask-SQLAlchemy without Flask

I had a small web service built using Flask and Flask-SQLAlchemy that only held one model. I now want to use the same database, but with a command line app, so I'd like to drop the Flask dependency.
My model looks like this:
class IPEntry(db.Model):
id = db.Column(db.Integer, primary_key=True)
ip_address = db.Column(db.String(16), unique=True)
first_seen = db.Column(db.DateTime(),
default = datetime.datetime.utcnow
)
last_seen = db.Column(db.DateTime(),
default = datetime.datetime.utcnow
)
#validates('ip')
def validate_ip(self, key, ip):
assert is_ip_addr(ip)
return ip
Since db will no longer be a reference to flask.ext.sqlalchemy.SQLAlchemy(app), how can I convert my model to use just SQLAlchemy. Is there a way for the two applications (one with Flask-SQLAlchemy the other with SQLAlchemy) to use the same database?
you can do this to replace db.Model:
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base
import sqlalchemy as sa
base = declarative_base()
engine = sa.create_engine(YOUR_DB_URI)
base.metadata.bind = engine
session = orm.scoped_session(orm.sessionmaker())(bind=engine)
# after this:
# base == db.Model
# session == db.session
# other db.* values are in sa.*
# ie: old: db.Column(db.Integer,db.ForeignKey('s.id'))
# new: sa.Column(sa.Integer,sa.ForeignKey('s.id'))
# except relationship, and backref, those are in orm
# ie: orm.relationship, orm.backref
# so to define a simple model
class UserModel(base):
__tablename__ = 'users' #<- must declare name for db table
id = sa.Column(sa.Integer,primary_key=True)
name = sa.Column(sa.String(255),nullable=False)
then to create the tables:
base.metadata.create_all()
That is how to use SQLAlchemy without Flask (for example to write a bulk of objects to PostgreSQL database):
from sqlalchemy import Column, Integer, String
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
# Define variables DB_USERNAME, DB_PASSWORD, DB_HOST, DB_PORT, DB_NAME
SQLALCHEMY_DATABASE_URI = f'postgresql://{DB_USERNAME}:{DB_PASSWORD}#{DB_HOST}:
{DB_PORT}/{DB_NAME}'
# ----- This is related code -----
engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=True)
Base = declarative_base()
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
Session.configure(bind=engine)
session = Session()
# ----- This is related code -----
class MyModel(Base):
__tablename__ = 'my_table_name'
id = Column(Integer, primary_key=True)
value = Column(String)
objects = [MyModel(id=0, value='a'), MyModel(id=1, value='b')]
session.bulk_save_objects(objects)
session.commit()
Check this one github.com/mardix/active-alchemy
Active-Alchemy is a framework agnostic wrapper for SQLAlchemy that makes it really easy to use by implementing a simple active record like api, while it still uses the db.session underneath. Inspired by Flask-SQLAlchemy
There is a great article about Flask-SQLAlchemy: how it works, and how to modify models to use them outside of Flask:
http://derrickgilland.com/posts/demystifying-flask-sqlalchemy/
The sqlalchemy docs has a good tutorial with examples that sound like what you want to do.
Shows how to connect to a db, mapping, schema creation, and querying/saving to the db.
This does not completely answer your question, because it does not remove Flask dependency, but you can use SqlAlchemy in scripts and tests by just not running the Flask app.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
test_app = Flask('test_app')
test_app.config['SQLALCHEMY_DATABASE_URI'] = 'database_uri'
test_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
metadata = MetaData(schema='myschema')
db = SQLAlchemy(test_app, metadata=metadata)
class IPEntry(db.Model):
pass
One difficulty you may encounter is the requirement of using db.Model as a base class for your models if you want to target the web app and independent scripts using same codebase. Possible way to tackle it is using dynamic polymorphism and wrap the class definition in a function.
def get_ipentry(db):
class IPEntry(db.Model):
pass
return IPEntry
As you construct the class run-time in the function, you can pass in different SqlAlchemy instances. Only downside is that you need to call the function to construct the class before using it.
db = SqlAlchemy(...)
IpEntry = get_ipentry(db)
IpEntry.query.filter_by(id=123).one()
Flask (> 1.0) attempt to provide helpers for sharing code between an web application and a command line interface; i personally think it might be cleaner, lighter and easier to build libraries unbound to flask, but you might want to check:
https://flask.palletsprojects.com/en/2.1.x/cli/
https://flask.palletsprojects.com/en/2.1.x/api/#flask.Flask.cli
Create database and table
import os
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
if os.path.exists('test.db'):
os.remove('test.db')
Base = declarative_base()
class Person(Base):
__tablename__ = 'person'
id = Column(Integer(), primary_key=True)
name = Column(String())
engine = create_engine('sqlite:///test.db')
Base.metadata.create_all(engine)
Using Flask_SQLAlchemy directly
from flask import Flask
from sqlalchemy import MetaData
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app, metadata=MetaData())
class Person(db.Model):
__tablename__ = 'person'
id = Column(Integer(), primary_key=True)
name = Column(String())
person = Person(name='Bob')
db.session.add(person)
db.session.commit()
print(person.id)

SQLAlchemy freezing application

I am using SQLAlchemy in my python command line app. The app is basically reading a set of URLs and doing inserts into a postgreql database based on the data.
After about the same number of inserts (give or take a few), the entire app freezes.
Having seen python sqlalchemy + postgresql program freezes I am assuming I am doing something wrong with the SQLAlchemy Session (although I am not using drop_all(), which seemed to be the cause of that issue). I've tried a couple of things but thus far they have had no impact.
Any hints or help would be welcome. If my integration of SQLAlchemy into my app is incorrect, a pointer to a good example of doing it right would also be welcome.
My code is as follows:
Set up the sql alchemy base:
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
Create the session info and attach it to the Base
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
engine = create_engine("sqlite:///myapp.db")
db_session = scoped_session(sessionmaker(bind=engine))
Base.query = db_session.query_property()
Base.scoped_db_session = db_session
Create my model from Base and make use of the session
class Person(Base):
def store(self):
if self.is_new():
self.scoped_db_session.add(self)
self.scoped_db_session.commit()
If I create enough objects of type Person and call store(), the app eventually freezes.
Managed to solve the problem. Turns out that my implementation is specifically on the don't do it this way list (see http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#session-frequently-asked-questions E.g. don't do this) and I was not managing the session correctly
To solve my problem I moved the session out of the model into a separate class, so instead of having calls like:
mymodel.store()
I now have:
db.current_session.store(mymodel)
where db is an instance of my custom DBContext below:
from contextlib import contextmanager
from sqlalchemy.orm import scoped_session, sessionmaker
class DbContext(object):
def __init__(self, engine, session=None):
self._engine = engine
self._session = session or scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=self._engine))
self.query = self._session.query_property()
self.current_session = None
def start_session(self):
self.current_session = self._session()
def end_session(self):
if self.current_session:
self.current_session.commit()
self.current_session.close()
self.current_session = None
#contextmanager
def new_session(self):
try:
self.start_session()
yield
finally:
self.end_session()
When you want to store one or more model objects, call DBContext.start_session() to start a clean session. When you finally want to commit, call DBContext.end_session().

How to use postgres numeric range with SQLAlchemy

I can't happen to find much on using Postgres range types in SQLAlchemy other than this. Does anyone know how to insert new column values into a numrange column? Does anyone have some code snippets or more documentation than the one I already found?
This has been added to the official documentation: https://bitbucket.org/zzzeek/sqlalchemy/issue/3046/postgresql-range-types-need-better
Had to dig around for this, but when in doubt, check the tests! The SQLAlchemy tests for the range types use the underlying psycopg2 types.
from psycopg2.extras import NumericRange
from sqlalchemy import create_engine, Column, Integer
from sqlalchemy.dialects.postgresql import INT4RANGE
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine('postgresql:///example', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base(bind=engine)
class Example(Base):
__tablename__ = 'example'
id = Column(Integer, primary_key=True)
window = Column(INT4RANGE, nullable=False)
Base.metadata.create_all()
session.add(Example(window=NumericRange(2, 6)))
session.add(Example(window=NumericRange(4, 8)))
session.commit()

Categories

Resources