2016-03-15 45 views
0

目标:创建一个跟踪/遵循另一个对象的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记录下来。我希望属性B跟踪属性A,以便即使应用程序重新启动(即从数据库重新加载属性),属性B将继续以反映对属性A的字典所做的更改。

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

+0

ClazzB是另一个模型吗?你需要坚持这种模式吗? – univerio

+0

@univerio是的,ClazzB也需要坚持。 – ChaimKut

+1

您的模型'ClazzA'和'ClazzB'在数据库级别有明确的关系吗?换句话说,如果我们只是得到一个类似“ClazzA.attributeA被更改为这个实例”的事件,有没有办法说“这个ClazzA实例与该ClazzB实例有关?”? –

回答

5

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') 

使用关系

定义模型和ClazzB之间ClazzArelationship。由于我们没有全貌,下面的定义只是一些例子。

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') 

现在不是增加的ClazzAattributeA参考,ClazzB相关objectA添加引用objectB的初始化。现在

objectB = ClazzB(..., objectA=objectA) 

两个是相关的,通过objectB访问的相关objectAattributeA

objectB.objectA.attributeA 

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

现在,如果你必须有一个属性attributeBClazzB(避免重构现有的代码或一些这样的),你可以添加属性

class ClazzB: 

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

将与

返回相关 objectAattributeA
objectB.attributeB 
objectB.attributeB['something'] = 'else' 

等等。

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

class ClazzB(Base): 

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

如果您希望ClazzB.attributeBJSONDict某些项下获得的值,比如,你可以使用类似这样

class ClazzB(Base): 

    key = Column(Unicode) 

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

您也可以attributeB工作作为一流水平的SQL表达式使用hybrid properties,如果你需要这样的事情。但是你必须自己编写你的类级表达式。