使用SQLAlchemy,如何建立动态关系?

时间:2012-04-26 17:10:48

标签: python synchronization python-3.x sqlalchemy

我有一个SyncEntities类(如下所示)。

我有几个与SyncEntities类相关的其他类(例如下面显示的CommodityTypes)。

我的所有Base子类都有此列uuidKey = Column(String, primary_key=True)

假设se是SyncEntities的一个实例。 se.entityKind是Base子类的名称。

如何查询se.uuidKey的se.entityKind类过滤中的对象?

class SyncEntities(Base):
    __tablename__ = 'SyncEntities'

    uuidKey = Column(String, primary_key=True)
    dateCreated = Column(DateTime, index=True)
    dateModified = Column(DateTime, index=True)
    dateSynced = Column(DateTime, index=True)
    username = Column(String)
    entityKind = Column(String)
    deleted = Column(Boolean)

    def __init__(self, entity, security):
        self.uuidKey = newUUID()
        self.dateCreated = security.now
        self.dateModified = security.now
        self.dateSynced = security.then
        self.username = security.username
        self.entityKind = entity.__tablename__
        self.deleted = False

    def modified(self, security):
        self.dateModified = security.now
        self.username = security.username

class CommodityTypes(Base):
    __tablename__ = 'CommodityTypes'
    uuidKey = Column(String, ForeignKey('SyncEntities.uuidKey'), primary_key=True)
    myName = Column(String, unique = True)
    sortKey = Column(Integer, unique = True)

    mySyncEntity = relationship("SyncEntities")

    def __init__(self, security, myName, sortKey):
        self.syncEntity = SyncEntities(self, security)
        self.uuidKey = self.syncEntity.uuidKey
        self.myName = myName
        self.sortKey = sortKey

1 个答案:

答案 0 :(得分:2)

此处的结构与“多态关联”类似,但不完全相同,您可以在此博客文章中了解此模式:http://techspot.zzzeek.org/2007/05/29/polymorphic-associations-with-sqlalchemy/。这是一篇旧帖子,但http://techspot.zzzeek.org/files/2007/discriminator_on_association.py的示例稍后作为更新示例添加。

这种情况略有不同,因为像CommodityTypes这样的对象只引用单个SyncEntities,而不是通常的多态关联中的多个。 SyncEntities也只能引用单一类型的相关对象,因为本地有entityKind。

我会注意到这个设计的一个潜在问题是你可能在其他表中有一些行,其中uuidKey指向特定的SyncEntities实例,但不是与“entityKind”匹配的类型。如果CommodityTypes和SyncEntities之间的关系实际上是一对一的,那么这会改变一切 - 这种模式非常简单地连接表继承,你可以使用http://docs.sqlalchemy.org/en/rel_0_7/orm/inheritance.html中描述的模式。

目标和SyncEntities之间也没有反射,这通常是自动执行这些查找样式的方法。但是你仍然可以使用entityKind类型查找类来近似:

def lookup_related(se):
    types = {
        'commodity':CommodityTypes,
        'foobar':FooBarTypes
    }
    cls = types[se.entityKind]
    session = object_session(se)
    return session.query(cls).filter(cls.mySyncEntity==se).all()

这里有一个mixin也可以使用backref:

class HasSyncEntity(object):
    entity_kind = None
    "subclasses need to populate this"

    @declared_attr
    def uuidKey(cls):
        return Column(String, ForeignKey("SyncEntities.uuidKey"), primary_key=True)

    @declared_attr
    def mySyncEntity(cls):
        return relationship("SyncEntities", backref="_%s_collection" % cls.entity_kind)

CommodityTypes变为:

class CommodityTypes(HasSyncEntity, Base):
    entity_kind = "commodity"
    # ...

然后你将这样的方法添加到SyncEntities,它会查找相应的backref,然后你就完成了:

def get_related(self):
    return getattr(self, "_%s_collection" % self.entityKind)