-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
EntityName
"entity_name" was a feature in very early versions of SQLAlchemy, through version 0.4, which allowed a class to be fully mapped multiple times to entirely different Table
objects. A string entity_name
parameter would be passed to most Session
methods indicating which mapping should be in use.
This approach was removed early on as it was extremely difficult to maintain and was never used. It also didn't really work, because a SQLAlchemy mapping makes modifications to the mapped class, so it's not really feasible to have many mappers against the exact same class, especially if these mappers intend to have differing behaviors or columns.
The entity_name
feature was adapted from Hibernate, where in the Java world creating a subclass is a very explicit and rigid affair. It turns out that in Python, this is not at all the case. Using type
we can easily make anonymous subclasses for each desired mapping. Here's first a "classical mapping" approach:
from sqlalchemy import *
from sqlalchemy.orm import *
metadata = MetaData(create_engine('sqlite://', echo=True))
t1 = Table('t1', metadata, Column('id', Integer, primary_key=True))
t2 = Table('t2', metadata, Column('id', Integer, primary_key=True))
metadata.create_all()
def map_class_to_some_table(cls, table, entity_name, **kw):
newcls = type(entity_name, (cls, ), {})
mapper(newcls, table, **kw)
return newcls
class Foo(object):
pass
T1Foo = map_class_to_some_table(Foo, t1, "T1Foo")
T2Foo = map_class_to_some_table(Foo, t2, "T2Foo")
sess = sessionmaker()()
sess.add_all([T1Foo(), T1Foo(), T2Foo(), T1Foo()])
print(sess.query(T1Foo).all())
print(sess.query(T2Foo).all())
With Declarative, we can use mixin classes:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class TBase(object):
"""Base class is a 'mixin'.
Guidelines for declarative mixins is at:
http://www.sqlalchemy.org/docs/orm/extensions/declarative.html#mixin-classes
"""
id = Column(Integer, primary_key=True)
data = Column(String(50))
def __repr__(self):
return "%s(data=%r)" % (
self.__class__.__name__, self.data
)
# build classes explicitly...
class T1Foo(TBase, Base):
__tablename__ = 't1'
class T2Foo(TBase, Base):
__tablename__ = 't2'
timestamp = Column(DateTime, default=func.now())
# or generate them with type()
T3Foo = type("T3Foo", (TBase, Base), {"__tablename__": "t3"})
engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)
sess = sessionmaker(engine)()
sess.add_all([T1Foo(data='t1'), T3Foo(data='t2'), T2Foo(data='t3'),
T1Foo(data='t4')])
print(sess.query(T1Foo).all())
print(sess.query(T2Foo).all())
print(sess.query(T3Foo).all())