【问题标题】:With SQLAlchemy, how do I make a dynamic relation?使用 SQLAlchemy,我如何建立动态关系?
【发布时间】:2012-05-07 11:10:03
【问题描述】:

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

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

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

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

如何查询 se.entityKind 类中的对象以筛选 se.uuidKey?

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

【问题讨论】:

    标签: python synchronization python-3.x sqlalchemy


    【解决方案1】:

    这里的结构与“多态关联”类似,但并不完全相同,您可以在这篇博文中了解这种模式: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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-06-16
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多