Change SQLAlchemy __tablename__ - python-3.x

I am using SQLAlchemy to handle requests from an API endpoint; my database tables (I have hundreds) are differentiated via a unique string (e.g. test_table_123)...
In the code below, __tablename__ is static. If possible, I would like that to change based on the specific table I would like to retrieve, as it would be tedious to write several hundred unique classes.
from config import db, ma # SQLAlchemy is init'd and tied to Flask in this config module
class specific_table(db.Model):
__tablename__ = 'test_table_123'
var1 = db.Column(db.Integer, primary_key=True)
var2 = db.Column(db.String, index=True)
var3 = db.Column(db.String)
class whole_table_schema(ma.ModelSchema):
class Meta:
model = specific_table
sqla_session = db.session
def single_table(table_name):
# collect the data from the unique table
my_data = specific_table().query.order_by(specific_table.level_0).all()
Thank you very much for your time in advance.

You can use reflect feature of SQLAlchemy.
engine = db.engine
metadata = MetaData()
metadata.reflect(bind=engine)
and finally
db.session.query(metadata.tables[table_name])
If you want smoother experience with querying, as previous solution cannot offer one, you might declare and map your tables: tables = {table_name: create_table(table_name) for table_name in table_names}, where create_table constructs models with different __tablename__. Instead of creating all tables at once, you can create them on demand.

Related

Eager loading of one particular attribute of a related object (sqlalchemy)

I declared the following models in sqlalchemy (python). My loading strategy is to use deferred as a default, and to modify my query when I need to avoid lazy loading.
What I'm trying to achieve is to get all legal_provision records, and have the related case_law items loaded at the same time, overruling the lazy loading (deferred) for the url column, but not for the other columns of case_law.
I don't seem to be able to find a convenient solution for this. Any help much appreciated!
ORM:
from sqlalchemy import Integer, String, Column, Table, ForeignKey
from sqlalchemy.orm import deferred, relationship, declarative_base
Base = declarative_base()
case_law_legal_provisions = Table(
'case_law_legal_provisions',
Column('case_law_id', ForeignKey('case_law.id'), primary_key=True),
Column('legal_provision_id', ForeignKey('legal_provision.id'), primary_key=True)
)
class LegalProvision(Base):
__tablename__ = 'legal_provision'
id = Column(Integer, primary_key=True)
reference = deferred(Column(String, unique=True))
case_law = relationship('CaseLaw', secondary='case_law_legal_provisions', backpopulates='legal_provisions')
class CaseLaw(Base):
__tablename__ = 'case_law'
id = Column(Integer, primary_key=True)
url = deferred(Column(String))
contents = deferred(Column(String))
legal_provisions = relationship('LegalProvision', secondary='case_law_legal_provisions', backpopulates='case_law')

colors = Color.query.all()

Hi I am trying to follow this tutorial to learn how to get pagination in my flask project.
https://betterprogramming.pub/simple-flask-pagination-example-4190b12c2e2e
I am having problems with the following line
"colors = Color.query.all()"
Where does "Color" come from ?
In all the tutorials I have read this form of variable appears but no explanation where it comes from
The Color class is a database model that was implemented with flask-SQLAlchemy. The class can be used to add, remove and query entries in a database table.
The definition of the model is as follows and contains three columns. The ID as a unique key for identification, the name of the color and a date when the database entry was added.
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
# ...
db = SQLAlchemy(app)
class Color(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False, unique=True, index=True)
created_at = db.Column(db.DateTime(timezone=True),
nullable=False, unique=False, index=False,
default=datetime.utcnow)
# ...
To use the database you have to create the necessary tables either via the flask shell or within your code like here.
with app.app_context():
db.create_all()
The flask-SQLAlchemy introductory example and the SQLAlchemy documentation explain more.
I also recommend this series of articles as a good tutorial for flask.
Have fun.

SQLAlchemy #event.listens_for(Class, 'after_insert') for SQL Expression "INSERT INTO table(cols) VALUES (values)"

In my application data will be flowing to postgres database from different system (from hive using scoop). I want to run some code automatically when it is inserted to one of the tables (I created it with sqlaLchemy ORM - I know that after_insert hook doesn't work for sqlAlchemy Core). And for my purpose I can't use postgres trigger.
This is kind of my data model:
from sqlalchemy.orm import declarative_base, Session
from sqlalchemy import Column, Integer, String, event, DDL
Base = declarative_base()
class MainClass(Base):
__tablename__ = 'first_table'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
#event.listens_for(MainClass, 'after_insert')
def after_insert(Mapper, connection, target):
connection.execute(DDL(f'''INSERT INTO second_table(name, value) VALUES ('OK!', '{target.name}')'''))
class SecondClass(Base):
__tablename__ = 'second_table'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
value = Column(String, nullable=False)
Base.metadata.create_all(engine, checkfirst=True)
What is not working:
engine.execute('''INSERT INTO first_table(name) VALUES ('test1')''')
What is working (but I can't use such insert in my case):
insert = MainClass(name='test2')
with Session(bind=engine) as session:
session.add(insert)
session.commit()
Documentations says:
method sqlalchemy.orm.MapperEvents.after_insert(mapper, connection, target)
Receive an object instance after an INSERT statement is emitted corresponding to that instance.
Example argument forms:
from sqlalchemy import event
#event.listens_for(SomeClass, 'after_insert')
def receive_after_insert(mapper, connection, target):
"listen for the 'after_insert' event"
This event is used to modify in-Python-only state on the instance after an INSERT occurs, as well as to emit additional SQL statements on the given connection.
The event is often called for a batch of objects of the same class after their INSERT statements have been emitted at once in a previous step. In the extremely rare case that this is not desirable, the mapper() can be configured with batch=False, which will cause batches of instances to be broken up into individual (and more poorly performing) event->persist->event steps.
If this is something that sqlAlchemy ORM events doesn't support. Can you recommend me some workaround?

Deletion of a row from an association table

I am working on an app using python3 and SqlAlchemy for SQLite3 database management. I have some tables that have a Many to Many relationship. I've created an association table to handle this relationship.
Class Machine(Base):
__tablename__ 'machine'
machine_ID = Column(Integer, primary_key=True)
etc...
Class Options(Base):
__tableName__ 'options'
options_ID = Column(Integer, primary_key=True)
etc...
The association table
Machine_Options = table('machine_options', Base.metadata,
Column('machine_FK', Integer, ForeignKey('machine.machine_ID'),
primary_key=True),
Column('options_FK',Integer, ForeignKey('options.options_ID'),
primary_key=True))
All the items for the Machine and Options are inserted independently. When I want to associate a machine with an option I use an append query which works very well.
My problem is when I want to break this association between a machine and an option. I have tried a direct row deletion from the association table using a FILTER() clause on the machine_FK and the options_FK but SqlAlchemy gives me an error informing me that 'Machine_Options' table has no field 'machine_FK'.
I have tried to remove the row from 'Machine_Options' indirectly using joins with the machine and options table but received another error that I can not delete or update using joins.
I am looking for the code to only delete a row from the association table without affecting the original machine or options table.
So far my internet search has been fruitless.
The answer to my problem is to use myparent.children.remove(somechild)
The association is made using machine.children.append(option)
Using the same code as the 'append' and substituting 'remove' unmakes the association
The code:
def removeOption(machineKey, OptionKey):
session = connectToDatabase()
machineData = session.query(Machine).filter(Machine.machine_ID == machineKey).one()
optionData = session.query(Options).filter(Options. options_ID == OptionKey).one()
machineData.children.remove(optionData)
session.add(machineData)
session.commit()
session.close()

Creating relationships with ORM Objects before inserting into a Database

Right now I have double the classes for the same data. The first are the Bill and the Expense class, used locally to exchange data within the program. I then I have Bill_Table and Expense_Table, used to exchange data between the program and database. This makes my program needlessly complicated, when I just want one of each.
Bill has a member variable that is a list of Expenses, like so:
class Bill:
vendor = None # type: str
expenses = None # type: list[Expense]
# plenty more variables here
def __init__(self, vendor=None,):
self.vendor = vendor
self.expenses = list()
class Expense:
account = None # type: str
amount = None # type: int
# etc...
My Bill_Table and Expense_Table are set up pretty much identical. I use some functions to convert a Bill into a Bill_table, or Expense into an Expense_Table, or visa versa.
from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Bill_Table(Base):
__tablename__ = 'bills'
id = Column(Integer, primary_key=True)
expenses = relationship("Expense_Table")
# etc...
class Expense_Table(Base):
__tablename__ = 'expenses'
id = Column(Integer, primary_key=True)
bill_id = Column(Integer, ForeignKey('bills.id'))
# etc...
How would I map some Expense_Table objects to a Bill_Table object, without connecting to a database? So I could have the same functionality, but also when I insert a Bill_Table into the database, it will also import it's Expense_Table objects with it too?

Resources