Reputation: 1
I am using SQLAlchemy + sqlacodegen in my python project. I have succesfully generated declarative model from my database, which looks like this:
DB_Model.py
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, Table
from sqlalchemy.sql.sqltypes import NullType
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
metadata = Base.metadata
class GameMatch(Base):
__tablename__ = 'GameMatches'
GameMatch_ID = Column(Integer, primary_key=True)
MatchDate = Column(DateTime)
UserCreated = Column(String(100))
class Player(Base):
__tablename__ = 'Players'
Player_ID = Column(Integer, primary_key=True)
Name = Column(String(255))
RollPerRound = Column(Integer)
class User(Base):
__tablename__ = 'Users'
User_ID = Column(Integer, primary_key=True)
Name = Column(String(255), nullable=False)
Code generating:
import io
import sys
import os
from sqlalchemy import create_engine, MetaData
from sqlacodegen.codegen import CodeGenerator
def generate_model(host, user, password, database, outfile = None):
engine = create_engine('sqlite:///' + os.getcwd() + "\\PigGameDB.db")
metadata = MetaData(bind=engine)
metadata.reflect()
outfile = io.open(outfile, 'w', encoding='utf-8') if outfile else sys.stdout
generator = CodeGenerator(metadata)
generator.render(outfile)
if __name__ == '__main__':
generate_model('database.example.org', 'dbuser', 'secretpassword', 'mydatabase', 'DB_Model.py')
I want to add functionality for these classes, but I can't add it directly into this model, because I have decided for Database first aproach - I define the database first, and then I use sqlacodegen to update the model. That means, that the model file is always rewritten with new generation.
I am thinking about using inheritance for these classes (wrapper) with desired functionality, or switch approach to code first (which i really not prefer).
What are the possible solutions for this problem? Links to good articles are welcomed too. As far as i know, in Python is no equivalent of partial class like in C#, which is solution for EntityFramework's database first approach.
Also is good approach to use these model classes directly in my project, or should I implement some mapping?
For example having class Player and _Player:
Player - class for table in the database, and used only for access to database.
_Player - class for the project itself, like standard python class.
Python 3.11.4 SQLAlchemy 1.4.49 sqlacodegen 2.3.0.post1
I tried searching for partial class C# equivalent for Python, with expectation, that class is divided to 2 sections - generated and written by hand.
Upvotes: 0
Views: 335
Reputation: 55589
There are a few ways that you might approach this, but the simplest solution is probably to generate tables rather than models (sqlacodegen has a TablesGenerator
class would help I think) and then use imperative mapping to map the tables to you classes. So you would have something like:
from sqlalchemy import orm
# Let's assume my_tables contains generated table definitions.
from my_tables import my_table1, my_table2
class MyClass1:
def method(self):
...
class MyClass2:
def method(self):
...
# Create a registry (you'll need to provide the metadata that contains your tables)
mapper_registry = orm.registry(metadata=my_table1.metadata)
# Map classes to tables.
mapper_registry.map_imperatively(MyClass1, my_table1)
mapper_registry.map_imperatively(MyClass2, my_table2)
Another approach would be to have your methods in mixin classes, and update the models file after it has been generated to inherit from the mixin as well as Base
. On a *nix platform you could do something like
sed -i '1i import mymixins' DB_models.py
sed -i 's/^class \([A-Z][a-z]\+\([A-Z][a-z]\+\)*\)(Base):/class \1(mymixins.\1Mixin, Base):/p' DB_Models.py
to get class Foo(mymixins.FooMixin, Base):
, for example.
Upvotes: 0