突变跟踪
支持跟踪对标量值的就地更改,这些更改将传播到所属父对象的ORM更改事件中。
建立标量列值的可变性
“可变”结构的一个典型例子是Python字典。遵循中介绍的示例 列和数据类型 ,我们从自定义类型开始,该类型在持久化之前将python字典封送到json字符串中:
from sqlalchemy.types import TypeDecorator, VARCHAR import json class JSONEncodedDict(TypeDecorator): "Represents an immutable structure as a json-encoded string." impl = VARCHAR def process_bind_param(self, value, dialect): if value is not None: value = json.dumps(value) return value def process_result_value(self, value, dialect): if value is not None: value = json.loads(value) return value
用法 json
只是为了举例。这个 sqlalchemy.ext.mutable
扩展可用于目标python类型可能可变的任何类型,包括 PickleType
, ARRAY
等。
当使用 sqlalchemy.ext.mutable
扩展名,值本身跟踪引用它的所有父级。下面,我们演示了 MutableDict
Dictionary对象,它应用 Mutable
混合到一个普通的python字典:
from sqlalchemy.ext.mutable import Mutable class MutableDict(Mutable, dict): @classmethod def coerce(cls, key, value): "Convert plain dictionaries to MutableDict." if not isinstance(value, MutableDict): if isinstance(value, dict): return MutableDict(value) # this call will raise ValueError return Mutable.coerce(key, value) else: return value def __setitem__(self, key, value): "Detect dictionary set events and emit change events." dict.__setitem__(self, key, value) self.changed() def __delitem__(self, key): "Detect dictionary del events and emit change events." dict.__delitem__(self, key) self.changed()
上面的dictionary类采用了对python内置子类化的方法 dict
产生一个dict子类,将所有突变事件通过 __setitem__
. 这种方法有一些变体,例如子类化 UserDict.UserDict
或 collections.MutableMapping
;对于这个例子来说,最重要的部分是 Mutable.changed()
每当发生对数据结构的就地更改时,都会调用方法。
我们还重新定义了 Mutable.coerce()
方法,该方法将用于转换不是 MutableDict
,例如 json
模块,放入适当的类型。定义这个方法是可选的;我们也可以创建 JSONEncodedDict
这样它总是返回 MutableDict
并确保所有调用代码都使用 MutableDict
明确地。什么时候? Mutable.coerce()
不重写,任何应用于父对象(不是可变类型的实例)的值都将引发 ValueError
.
我们的新 MutableDict
类型提供类方法 Mutable.as_mutable()
我们可以在列元数据中使用它来与类型关联。此方法获取给定的类型对象或类,并关联一个侦听器,该侦听器将检测此类型的所有未来映射,并将事件侦听工具应用于映射的属性。例如,使用经典表元数据:
from sqlalchemy import Table, Column, Integer my_data = Table('my_data', metadata, Column('id', Integer, primary_key=True), Column('data', MutableDict.as_mutable(JSONEncodedDict)) )
上面, Mutable.as_mutable()
返回的实例 JSONEncodedDict
(如果类型对象已经不是实例),它将截获针对此类型映射的任何属性。下面我们根据 my_data
表:
from sqlalchemy import mapper class MyDataClass(object): pass # associates mutation listeners with MyDataClass.data mapper(MyDataClass, my_data)
这个 MyDataClass.data
现在将通知成员其值的就地更改。
使用声明性时,用法没有区别:
from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class MyDataClass(Base): __tablename__ = 'my_data' id = Column(Integer, primary_key=True) data = Column(MutableDict.as_mutable(JSONEncodedDict))
对 MyDataClass.data
成员将在父对象上将属性标记为“脏的”::
>>> from sqlalchemy.orm import Session >>> sess = Session() >>> m1 = MyDataClass(data={'value1':'foo'}) >>> sess.add(m1) >>> sess.commit() >>> m1.data['value1'] = 'bar' >>> assert m1 in sess.dirty True
这个 MutableDict
可以与以后的所有实例关联 JSONEncodedDict
一步到位,使用 Mutable.associate_with()
. 这和 Mutable.as_mutable()
但它会截获 MutableDict
在所有映射中,无条件地,无需单独声明:
MutableDict.associate_with(JSONEncodedDict) class MyDataClass(Base): __tablename__ = 'my_data' id = Column(Integer, primary_key=True) data = Column(JSONEncodedDict)
配套酸洗
关键在于 sqlalchemy.ext.mutable
扩展依赖于 weakref.WeakKeyDictionary
在value对象上,它存储一个父映射对象的映射,这些对象的键控对象是与该值关联的属性名。 WeakKeyDictionary
对象是不可拾取的,因为它们包含weakerfs和函数回调。在我们的例子中,这是一件好事,因为如果这个字典是可挑选的,它可能会导致我们的值对象的pickle大小过大,而这些对象本身在父对象的上下文之外被pickle。开发者的职责只是提供 __getstate__
排除 MutableBase._parents()
泡菜流收集:
class MyMutableType(Mutable): def __getstate__(self): d = self.__dict__.copy() d.pop('_parents', None) return d
使用字典示例,我们需要返回dict本身的内容(并在 __setstate__) ::
class MutableDict(Mutable, dict): # .... def __getstate__(self): return dict(self) def __setstate__(self, state): self.update(state)
如果可变值对象在附加到一个或多个也是pickle一部分的父对象时被pickle,则 Mutable
Mixin将重新建立 Mutable._parents
取消拾取每个值对象上作为所属父对象本身的集合。
接收事件
这个 AttributeEvents.modified()
事件处理程序可用于在可变标量发出更改事件时接收事件。当 flag_modified()
从可变扩展名内调用函数:
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import event Base = declarative_base() class MyDataClass(Base): __tablename__ = 'my_data' id = Column(Integer, primary_key=True) data = Column(MutableDict.as_mutable(JSONEncodedDict)) @event.listens_for(MyDataClass.data, "modified") def modified_json(instance): print("json value modified:", instance.data)
确定复合材料的易变性
复合是一种特殊的ORM特性,它允许为单个标量属性分配一个对象值,该对象值表示来自底层映射表中一个或多个列的“复合”信息。通常的例子是几何“点”的例子,并在 组合列类型 .
情况也是如此 Mutable
,用户定义的复合类子类 MutableComposite
作为一个混合,并通过 MutableComposite.changed()
方法。对于复合类,通常通过使用python描述符(即 @property
或者通过特殊的python方法 __setattr__()
. 下面我们将展开 Point
在中引入的类 组合列类型 子类 MutableComposite
以及通过 __setattr__
到 MutableComposite.changed()
方法:
from sqlalchemy.ext.mutable import MutableComposite class Point(MutableComposite): def __init__(self, x, y): self.x = x self.y = y def __setattr__(self, key, value): "Intercept set events" # set the attribute object.__setattr__(self, key, value) # alert all parents to the change self.changed() def __composite_values__(self): return self.x, self.y def __eq__(self, other): return isinstance(other, Point) and \ other.x == self.x and \ other.y == self.y def __ne__(self, other): return not self.__eq__(other)
这个 MutableComposite
类使用python元类自动建立侦听器,以便使用 composite()
这说明了我们 Point
类型。下面,什么时候 Point
映射到 Vertex
类,将建立侦听器,用于路由更改事件 Point
对象 Vertex.start
和 Vertex.end
属性::
from sqlalchemy.orm import composite, mapper from sqlalchemy import Table, Column vertices = Table('vertices', metadata, Column('id', Integer, primary_key=True), Column('x1', Integer), Column('y1', Integer), Column('x2', Integer), Column('y2', Integer), ) class Vertex(object): pass mapper(Vertex, vertices, properties={ 'start': composite(Point, vertices.c.x1, vertices.c.y1), 'end': composite(Point, vertices.c.x2, vertices.c.y2) })
对 Vertex.start
或 Vertex.end
成员将在父对象上将属性标记为“脏的”::
>>> from sqlalchemy.orm import Session >>> sess = Session() >>> v1 = Vertex(start=Point(3, 4), end=Point(12, 15)) >>> sess.add(v1) >>> sess.commit() >>> v1.end.x = 8 >>> assert v1 in sess.dirty True
胁迫可变复合材料
这个 MutableBase.coerce()
复合类型也支持方法。在情况下 MutableComposite
, the MutableBase.coerce()
方法只对属性集操作调用,而不是对加载操作调用。重写 MutableBase.coerce()
方法本质上等同于使用 validates()
使用自定义复合类型的所有属性的验证例程:
class Point(MutableComposite): # other Point methods # ... def coerce(cls, key, value): if isinstance(value, tuple): value = Point(*value) elif not isinstance(value, Point): raise ValueError("tuple or Point expected") return value
配套酸洗
情况也是如此 Mutable
, the MutableComposite
帮助程序类使用 weakref.WeakKeyDictionary
可通过 MutableBase._parents()
不可选择的属性。如果我们需要pickle Point
或者它所属的阶级 Vertex
我们至少需要定义 __getstate__
不包括 _parents
字典。下面我们定义两个 __getstate__
和A __setstate__
把我们 Point
班级:
class Point(MutableComposite): # ... def __getstate__(self): return self.x, self.y def __setstate__(self, state): self.x, self.y = state
和一样 Mutable
, the MutableComposite
增加父对象关系状态的酸洗过程,以便 MutableBase._parents()
集合已还原为所有 Point
物体。
API引用
Object Name | Description |
---|---|
定义将更改事件透明传播到父对象的mixin。 | |
公共基类到 | |
mixin,它定义了将SQLAlchemy“composite”对象上的更改事件透明传播到其所属父对象或父对象。 | |
实现的字典类型 | |
实现的列表类型 | |
实现的集合类型 |
- class sqlalchemy.ext.mutable.MutableBase¶
公共基类到
Mutable
和MutableComposite
.- attribute
sqlalchemy.ext.mutable.MutableBase.
_parents¶ 父对象的字典
InstanceState
->父级上的属性名称。此属性是所谓的“memoized”属性。它用一个新的
weakref.WeakKeyDictionary
第一次访问它时,在随后访问时返回同一对象。在 1.4 版更改: 这个
InstanceState
现在用作弱字典中的键,而不是用作实例本身。
- method
sqlalchemy.ext.mutable.MutableBase.
classmethod coerce(key, value)¶ 给定一个值,将其强制为目标类型。
可以被自定义子类重写,以将传入数据强制为特定类型。
默认情况下,加薪
ValueError
.根据父类的类型,在不同的方案中调用此方法
Mutable
或类型MutableComposite
. 对于前者,在属性集操作和ORM加载操作期间都会调用它。对于后者,只在属性集操作期间调用;composite()
在加载操作期间构造句柄强制。
- attribute
- class sqlalchemy.ext.mutable.Mutable¶
定义将更改事件透明传播到父对象的mixin。
参见中的示例 建立标量列值的可变性 有关用法信息。
类签名
class
sqlalchemy.ext.mutable.Mutable
(sqlalchemy.ext.mutable.MutableBase
)- method
sqlalchemy.ext.mutable.Mutable.
classmethod _get_listen_keys(attribute)¶ inherited from the
sqlalchemy.ext.mutable.MutableBase._get_listen_keys
method ofMutableBase
给定一个描述符属性,返回
set()
指示此属性状态更改的属性键。这通常只是
set([attribute.key])
,但可以重写以提供其他键。例如MutableComposite
使用与组成复合值的列关联的属性键扩充此集合。如果截取
InstanceEvents.refresh()
和InstanceEvents.refresh_flush()
事件,传递已刷新的属性名列表;将列表与此集合进行比较,以确定是否需要执行操作。1.0.5 新版功能.
- method
sqlalchemy.ext.mutable.Mutable.
classmethod _listen_on_attribute(attribute, coerce, parent_cls)¶ inherited from the
sqlalchemy.ext.mutable.MutableBase._listen_on_attribute
method ofMutableBase
将此类型建立为给定映射描述符的突变侦听器。
- attribute
sqlalchemy.ext.mutable.Mutable.
_parents¶ inherited from the
sqlalchemy.ext.mutable.MutableBase._parents
attribute ofMutableBase
父对象的字典
InstanceState
->父级上的属性名称。此属性是所谓的“memoized”属性。它用一个新的
weakref.WeakKeyDictionary
第一次访问它时,在随后访问时返回同一对象。在 1.4 版更改: 这个
InstanceState
现在用作弱字典中的键,而不是用作实例本身。
- method
sqlalchemy.ext.mutable.Mutable.
classmethod as_mutable(sqltype)¶ 将SQL类型与此可变的python类型关联。
这将建立监听器,用于检测给定类型的ORM映射,并向这些映射添加突变事件跟踪器。
将无条件地作为实例返回类型,以便
as_mutable()
可以直接使用::Table('mytable', metadata, Column('id', Integer, primary_key=True), Column('data', MyMutableType.as_mutable(PickleType)) )
请注意,返回的类型始终是一个实例,即使给定了一个类,并且只有用该类型实例专门声明的列才能接收额外的检测。
要将特定可变类型与特定类型的所有出现关联,请使用
Mutable.associate_with()
特殊的分类方法Mutable
子类以建立全局关联。警告
通过这种方法建立的侦听器是 全球的 所有映射器,并且 not 垃圾收集。只使用
as_mutable()
对于应用程序的永久类型,而不是特殊类型,否则这将导致内存使用量的无限增长。
- method
sqlalchemy.ext.mutable.Mutable.
classmethod associate_with(sqltype)¶ 将此包装与给定类型的所有未来映射列相关联。
这是一个调用
associate_with_attribute
自动地。警告
通过这种方法建立的侦听器是 全球的 所有映射器,并且 not 垃圾收集。只使用
associate_with()
对于应用程序的永久类型,而不是特殊类型,否则这将导致内存使用量的无限增长。
- method
sqlalchemy.ext.mutable.Mutable.
classmethod associate_with_attribute(attribute)¶ 将此类型建立为给定映射描述符的突变侦听器。
- method
sqlalchemy.ext.mutable.Mutable.
changed()¶ 每当发生更改事件时,子类应该调用此方法。
- method
sqlalchemy.ext.mutable.Mutable.
classmethod coerce(key, value)¶ inherited from the
MutableBase.coerce()
method ofMutableBase
给定一个值,将其强制为目标类型。
可以被自定义子类重写,以将传入数据强制为特定类型。
默认情况下,加薪
ValueError
.根据父类的类型,在不同的方案中调用此方法
Mutable
或类型MutableComposite
. 对于前者,在属性集操作和ORM加载操作期间都会调用它。对于后者,只在属性集操作期间调用;composite()
在加载操作期间构造句柄强制。
- method
- class sqlalchemy.ext.mutable.MutableComposite¶
mixin,它定义了将SQLAlchemy“composite”对象上的更改事件透明传播到其所属父对象或父对象。
参见中的示例 确定复合材料的易变性 有关用法信息。
类签名
class
sqlalchemy.ext.mutable.MutableComposite
(sqlalchemy.ext.mutable.MutableBase
)- method
sqlalchemy.ext.mutable.MutableComposite.
changed()¶ 每当发生更改事件时,子类应该调用此方法。
- method
- class sqlalchemy.ext.mutable.MutableDict¶
实现的字典类型
Mutable
.这个
MutableDict
对象实现一个字典,当字典的内容发生更改时(包括添加或删除值时),该字典将向基础映射发出更改事件。注意
MutableDict
做 not 将可变跟踪应用于 价值观本身 在字典里。因此,对于跟踪深度更改到 递归的 字典结构,如JSON结构。要支持此用例,请构建MutableDict
它对字典中的值进行适当的强制,使它们也“可变”,并向其父结构发出事件。参见
类签名
class
sqlalchemy.ext.mutable.MutableDict
(sqlalchemy.ext.mutable.Mutable
,builtins.dict
)- method
sqlalchemy.ext.mutable.MutableDict.
clear() → None. Remove all items from D.¶
- method
sqlalchemy.ext.mutable.MutableDict.
classmethod coerce(key, value)¶ 将普通字典转换为此类的实例。
- method
sqlalchemy.ext.mutable.MutableDict.
pop(k[, d]) → v, remove specified key and return the corresponding value.¶ 如果找不到键,则返回d(如果给定),否则将引发keyError
- method
sqlalchemy.ext.mutable.MutableDict.
popitem() → (k, v), remove and return some (key, value) pair as a¶ 2元组;但如果d为空,则引发keyror。
- method
sqlalchemy.ext.mutable.MutableDict.
setdefault(key, value)¶ 如果关键字不在字典中,则插入值为默认值的关键字。
如果键在字典中,则返回键的值,否则为默认值。
- method
sqlalchemy.ext.mutable.MutableDict.
update([E, ]**F) → None. Update D from dict/iterable E and F.¶ 如果e存在并且有.keys()方法,那么对e:d中的k执行:操作 [k] = e [k] 如果e存在,并且缺少.keys()方法,则为:对于k,e:d中的v [k] =v在任何一种情况下,后面跟着:对于f:d中的k [k] = f [k]
- method
- class sqlalchemy.ext.mutable.MutableList(iterable=(), /)¶
实现的列表类型
Mutable
.这个
MutableList
对象实现一个列表,该列表将在更改列表内容时(包括添加或删除值时)向基础映射发出更改事件。注意
MutableList
做 not 将可变跟踪应用于 价值观本身 在列表中。因此,对于跟踪深度更改到 递归的 可变结构,如JSON结构。要支持此用例,请构建MutableList
它对字典中的值进行适当的强制,使它们也“可变”,并向其父结构发出事件。1.1 新版功能.
参见
类签名
class
sqlalchemy.ext.mutable.MutableList
(sqlalchemy.ext.mutable.Mutable
,builtins.list
)- method
sqlalchemy.ext.mutable.MutableList.
append(x)¶ 将对象追加到列表末尾。
- method
sqlalchemy.ext.mutable.MutableList.
clear()¶ 从列表中删除所有项目。
- method
sqlalchemy.ext.mutable.MutableList.
classmethod coerce(index, value)¶ 将普通列表转换为此类的实例。
- method
sqlalchemy.ext.mutable.MutableList.
extend(x)¶ 通过从iterable附加元素来扩展列表。
- method
sqlalchemy.ext.mutable.MutableList.
insert(i, x)¶ 在索引前插入对象。
- method
sqlalchemy.ext.mutable.MutableList.
pop(*arg)¶ 移除并返回索引处的项(默认最后一个)。
如果列表为空或索引超出范围,则引发IndexError。
- method
sqlalchemy.ext.mutable.MutableList.
remove(i)¶ 删除第一次出现的值。
如果值不存在,则引发ValueError。
- method
sqlalchemy.ext.mutable.MutableList.
reverse()¶ 反向 就位 .
- method
sqlalchemy.ext.mutable.MutableList.
sort(**kw)¶ 稳定排序 就位 .
- method
- class sqlalchemy.ext.mutable.MutableSet¶
实现的集合类型
Mutable
.这个
MutableSet
对象实现一个集合,该集合将在更改集合内容时(包括添加或删除值时)向基础映射发出更改事件。注意
MutableSet
做 not 将可变跟踪应用于 价值观本身 在布景里。因此,对于跟踪深度更改到 递归的 可变结构。要支持此用例,请构建MutableSet
它对字典中的值进行适当的强制,使它们也“可变”,并向其父结构发出事件。1.1 新版功能.
参见
类签名
class
sqlalchemy.ext.mutable.MutableSet
(sqlalchemy.ext.mutable.Mutable
,builtins.set
)- method
sqlalchemy.ext.mutable.MutableSet.
add(elem)¶ 向集合中添加元素。
如果元素已经存在,则此操作无效。
- method
sqlalchemy.ext.mutable.MutableSet.
clear()¶ 删除此集合中的所有元素。
- method
sqlalchemy.ext.mutable.MutableSet.
classmethod coerce(index, value)¶ 将普通集转换为此类的实例。
- method
sqlalchemy.ext.mutable.MutableSet.
difference_update(*arg)¶ 从此集合中移除另一集合的所有元素。
- method
sqlalchemy.ext.mutable.MutableSet.
discard(elem)¶ 如果元素是成员,则将其从集合中移除。
如果元素不是成员,则不执行任何操作。
- method
sqlalchemy.ext.mutable.MutableSet.
intersection_update(*arg)¶ 用自身和另一个的交集更新集合。
- method
sqlalchemy.ext.mutable.MutableSet.
pop(*arg)¶ 移除并返回任意集合元素。如果集合为空,则引发keyError。
- method
sqlalchemy.ext.mutable.MutableSet.
remove(elem)¶ 从集合中移除元素;它必须是成员。
如果元素不是成员,则引发keyError。
- method
sqlalchemy.ext.mutable.MutableSet.
symmetric_difference_update(*arg)¶ 使用自身和另一个的对称差异更新集。
- method
sqlalchemy.ext.mutable.MutableSet.
update(*arg)¶ 使用自身和其他集合更新集合。
- method