Package: sa2django
SqlAlchemy to Django BridgeConvert sqlalchemy database schemas to django database models at runtime.Original url:https://github.com/mariushelf/sa2djangoThe SQLAlchemy to Django Bridge allows to specify your data models in SQLAlchemy
and use them in Django, without manually re-specifying all your models and fields
for the Django ORM.Why this package?Specifying a schema in SQLAlchemy and then using it in Django sounds like... counter-
intuitive. There are a lot ofWhy notsto answer...Why not specify your models in Django straight away?Sometimes some or all of the data you serve from Django is maintained or created
by sources that are not part of the Django application. If those sources already specify
a complete SQLAlchemy model, then the SQLAlchemy to Django bridge is useful.Why not simply useinspectdbto dynamically generate the Django model specifications?inspectdbis not
that dynamic after all -- it generates a Python file once, which needs to be manually
tweaked. And each time the data model changes, you need to adjust that Python file.Also it is often not possible to automatically derive all relations between models
from the database. With third-party datasources, often relations are not manifested
as foreign key constraints in the database schema, but just in some documentation
that explains the relations in human-, but not machine-readable form.If the SQLAlchemy models already contain all those relations then it makes sense to
convert the SQLAlchemy models to Django ORMat runtime.StatusThe SQLAlchemy to Django Bridge works well for the author's use case.There are probably a lot of corner cases and advanced (or not so advanced) features
of SQLAlchemy that are not (yet) supported.The tests run in sqlite, and our production system uses PostgreSQL.
It may or may not work with other database systems.Installationpip install sa2djangoFeaturesbasic data types (int, float, string, varchar, char, date, datetime etc, bytea)foreign keys and many-to-one relationshipsmany-to-many relationships includingthroughtablesautomatic inference of all declared models in a sqlalchemyBasealternatively define your Django models as usual, but use theSA2DModelas
base class. Then all database fields are added from the corresponding sqlalchemy
model, but you can still add properties and functions to the Django modelUsageDefine your SQLAlchemy schemaSay you have the following SQLAlchemy schema:# sqlalchemy_schema.pyfromsqlalchemyimportColumn,ForeignKey,Integer,Stringfromsqlalchemy.ext.declarativeimportdeclarative_basefromsqlalchemy.ormimportrelationshipBase=declarative_base()classParent(Base):__tablename__="parent"id=Column(Integer,primary_key=True)name=Column(String)children=relationship("Child",back_populates="parent")classChild(Base):__tablename__="child"id=Column(Integer,primary_key=True)name=Column(String)age=Column(Integer)parent_id=Column(Integer,ForeignKey("parent.id"))parent=relationship(Parent,uselist=False,back_populates="children")Automatic inferenceYou can use it in your Django application by simply adding the following code to
yourmodels.py:# models.pyfromsa2django.coreimportgenerate_sa2d_models,inject_modelsfromsqlalchemy_modelsimportBase# this is what we have specified in the snippet above_models=generate_sa2d_models(Base,__name__)inject_models(_models,globals())This will add the classesChildandParentto yourmodelsmodule.
These classes are the Django models that correspond to the SQLAlchemy models.You can't see it in the file, but Django will recognize them, and you can import them
anywhere in the application as if you had declared them manually:frommodelsimportParent,Childprint(Child.objects.all())child=Child.objects.get(pk=my_pk)print(child.parents.all())Note:your IDE might complain because it thinks thatParentandChilddo not
exist. It can't know, because the classes are created at runtime. The code will work
fine.Manual specification and custom propertiesA strength of Django is that it allows to specify additional properties on a model.
sa2django supports this. To do so you can declare your models explicitly and inherit
fromsa2django.SA2DModelinstead ofdjango.db.models.Model, and specify the
corresponding SQLAlchemy model in theMetaclass under thesa_modelattribute.You also need to registerallDjango models that are referenced by any model in the
SQLAlchemy schema withregister_table().Then you have control over the class name and additional properties and usesa2djangoonly to add all fields and relations to your Django model.Here's and example:fromsa2djangoimportregister_table,SA2DModelfromsa2django.coreimportextract_tables_from_baseimportsqlalchemy_models# extract all SQLAlchemy tables_tables=extract_tables_from_base(sqlalchemy_models.Base)# register the tablesfor_tablename,_sa_classin_tables.items():register_table(_tablename,_sa_class.__name__)classChild(SA2DModel):classMeta:sa_model=sqlalchemy_models.Childordering=["age"]@propertydefage_next_year(self):returnself.age+1classParent(SA2DModel):classMeta:sa_model=sqlalchemy_models.ParentAt the moment it is not possible to mix manual and automatic model extraction --
if you specify one model manually, you cannot usegenerate_sa2d_models()anymore,
so you need to specifyallmodels manually.LimitationsSQLAlchemy provides a superset of Django's functionality. For this reason, there's a
long list of limitations.The list is even longer and probably not exhaustive because sa2django is a young project
tailored to its author's current needs.at the moment only declarative base definitions are supported, no pureMapperobjectscomposite foreign keys and primary keys are not supported. Primary keys and foreign
keys must contain exactly one columnrelations that do not use a foreign key are not added to the Django modelsMany to many relationshipsIn sqlalchemy, in the mapper of the intermediate table, both foreign keysandrelationships linking to both tables must be specified.Example:classCarParentAssoc(Base):__tablename__="cartoparent"id=Column(Integer,primary_key=True)car=relationship("Car")parent=relationship("Parent")car_id=Column(Integer,ForeignKey("car.car_id"))parent_id=Column(Integer,ForeignKey("parent.id"))Note that for both links to thecarandparenttable, both foreign keys and
relationship attributes are specified.Changelog0.2.1limit to SQLAlchemy <1.40.2.0derive foreignkeys from MANYTOONE relationships instead of relying on explicit
ForeignKey columns0.1.3set arbitrarymax_lengthof 2048 on String fields that do not have a defined length
in sqlalchemy. Necessary because Django does not support unlimited String fields, even
though some backends (e.g., Postgres) doContributingPull requests are more than welcome! Ideally reach out to us by creating or replying
to a Github ticket such that we can align our work and ideas.LicenseMITAuthor: Marius Helf
(helfsmarius@gmail.com)