用于跟踪指定属性的SqlAlchemy属性

时间:2016-03-15 13:52:04

标签: python sqlalchemy

目标:创建一个SQLAlchemy属性,该属性跟踪/跟踪另一个对象的SQLAlchemy属性中的更改。

假设:

class ClazzA():
    attributeA = Column(JSONDict)

class ClazzB():
    attributeB = Column(?)

objectA = ClazzA()
objectA.attributeA = {'foo': 1}
objectB = ClazzB()
objectB.attributeB = objectA.attributeA
objectA.attributeA['foo'] = 2

JSONDictMutableDict相关联,如此处所述:http://docs.sqlalchemy.org/en/latest/orm/extensions/mutable.html#module-sqlalchemy.ext.mutable,即JSONDict类型允许进行变异跟踪。

因此我们在objectA上有这个字典,其更改由SQLAlchemy记录。我希望attributeB跟踪attributeA,这样即使重新启动应用程序(即从DB重新加载属性),attributeB也将继续以反映对attributeA&#39的字典所做的更改。

当然,这与Python doesn't have an idea of pointers的事实密切相关。我想知道SQLAlchemy是否有针对这个特定问题的解决方案。

1 个答案:

答案 0 :(得分:6)

TL; DR

您需要one-to-many关系。

from sqlalchemy import ForeignKey, Integer, Column
from sqlalchemy.orm import relationship


class Widget(Base):

    __tablename__ = 'widget'

    widget_id = Column(Integer, primary_key=True)
    # name columns, type columns, ...
    json = Column(JSONDict)


class ClazzB(Base):

    __tablename__ = 'clazzb'

    clazzb_id = Column(Integer, primary_key=True)
    # Your "attributeB"
    widget_id = Column(Integer,
                       ForeignKey('widget.widget_id',
                                  onupdate='cascade',
                                  ondelete='cascade'),
                       nullable=False)

    widget = relationship('Widget')
    # possible association_proxy
    #widget_json = association_proxy('widget', 'json')

使用关系

在模型ClazzAClazzB之间定义relationship。既然我们没有全局,下面的定义就是例子。

from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship


class ClazzA(Base):  # replace Base with the base class of your models

    __tablename__ = 'clazza'  # replace with the real tablename

    # T is the type of your primary key, the column name is just an example
    clazza_id = Column(T, primary_key=True)


class ClazzB(Base):

    # The column that will relate this model to ClazzA
    clazza_id = Column(T, ForeignKey('clazza.clazza_id',
                                     onupdate='cascade',
                                     ondelete='cascade'),
                       nullable=False)

    # A handy accessor for relationship between mapped classes,
    # not strictly required. Configurable to be either very lazy
    # (loaded if accessed by issuing a SELECT) or eager (JOINed
    # when loading objectB for example)
    objectA = relationship('ClazzA')

现在,而不是在attributeA的{​​{1}}添加对ClazzA的引用,而不是在初始化时添加对相关ClazzBobjectA的引用。

objectB

这两者现已相关,并通过objectB = ClazzB(..., objectA=objectA) 来访问相关attributeA的{​​{1}}

objectA

无需跟踪objectB的更改,因为它是实例的objectB.objectA.attributeA

现在,如果您必须在attributeA上拥有属性attributeA(为了避免重构现有代码或其他类似代码),您可以添加属性

attributeB

将使用

返回相关ClazzB的{​​{1}}
class ClazzB:

    @property
    def attributeB(self):
        return self.objectA.attributeA

等等。

还有一种用于跨关系访问属性的SQLAlchemy方法:association proxy。它支持简单的查询,但不是例如可订阅的。

attributeA

如果您希望objectA访问特定密钥下objectB.attributeB objectB.attributeB['something'] = 'else' 的值,您可以使用类似的内容

class ClazzB(Base):

    attributeB = association_proxy('objectA', 'attributeA')

如果您需要这样的话,还可以使用hybrid properties使ClazzB.attributeB在类级别上作为SQL表达式工作。您必须自己编写类级表达式。