目标:创建一个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
JSONDict
与MutableDict
相关联,如此处所述: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是否有针对这个特定问题的解决方案。
答案 0 :(得分:6)
您需要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')
在模型ClazzA
和ClazzB
之间定义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
的引用,而不是在初始化时添加对相关ClazzB
到objectA
的引用。
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表达式工作。您必须自己编写类级表达式。