支持跟踪对标量值的就地更改,这些更改将传播到所属父对象的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
物体。
Object Name | Description |
---|---|
定义将更改事件透明传播到父对象的mixin。 |
|
公共基类到 |
|
mixin,它定义了将SQLAlchemy“composite”对象上的更改事件透明传播到其所属父对象或父对象。 |
|
实现的字典类型 |
|
实现的列表类型 |
|
实现的集合类型 |
公共基类到 Mutable
和 MutableComposite
.
sqlalchemy.ext.mutable.MutableBase.
_parents¶父对象的字典 InstanceState
->父级上的属性名称。
此属性是所谓的“memoized”属性。它用一个新的 weakref.WeakKeyDictionary
第一次访问它时,在随后访问时返回同一对象。
在 1.4 版更改: 这个 InstanceState
现在用作弱字典中的键,而不是用作实例本身。
sqlalchemy.ext.mutable.MutableBase.
classmethod coerce(key, value)¶给定一个值,将其强制为目标类型。
可以被自定义子类重写,以将传入数据强制为特定类型。
默认情况下,加薪 ValueError
.
根据父类的类型,在不同的方案中调用此方法 Mutable
或类型 MutableComposite
. 对于前者,在属性集操作和ORM加载操作期间都会调用它。对于后者,只在属性集操作期间调用; composite()
在加载操作期间构造句柄强制。
定义将更改事件透明传播到父对象的mixin。
参见中的示例 建立标量列值的可变性 有关用法信息。
sqlalchemy.ext.mutable.Mutable.
classmethod _get_listen_keys(attribute)¶inherited from the sqlalchemy.ext.mutable.MutableBase._get_listen_keys
method of MutableBase
给定一个描述符属性,返回 set()
指示此属性状态更改的属性键。
这通常只是 set([attribute.key])
,但可以重写以提供其他键。例如 MutableComposite
使用与组成复合值的列关联的属性键扩充此集合。
如果截取 InstanceEvents.refresh()
和 InstanceEvents.refresh_flush()
事件,传递已刷新的属性名列表;将列表与此集合进行比较,以确定是否需要执行操作。
1.0.5 新版功能.
sqlalchemy.ext.mutable.Mutable.
classmethod _listen_on_attribute(attribute, coerce, parent_cls)¶inherited from the sqlalchemy.ext.mutable.MutableBase._listen_on_attribute
method of MutableBase
将此类型建立为给定映射描述符的突变侦听器。
sqlalchemy.ext.mutable.Mutable.
_parents¶inherited from the sqlalchemy.ext.mutable.MutableBase._parents
attribute of MutableBase
父对象的字典 InstanceState
->父级上的属性名称。
此属性是所谓的“memoized”属性。它用一个新的 weakref.WeakKeyDictionary
第一次访问它时,在随后访问时返回同一对象。
在 1.4 版更改: 这个 InstanceState
现在用作弱字典中的键,而不是用作实例本身。
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()
对于应用程序的永久类型,而不是特殊类型,否则这将导致内存使用量的无限增长。
sqlalchemy.ext.mutable.Mutable.
classmethod associate_with(sqltype)¶将此包装与给定类型的所有未来映射列相关联。
这是一个调用 associate_with_attribute
自动地。
警告
通过这种方法建立的侦听器是 全球的 所有映射器,并且 not 垃圾收集。只使用 associate_with()
对于应用程序的永久类型,而不是特殊类型,否则这将导致内存使用量的无限增长。
sqlalchemy.ext.mutable.Mutable.
classmethod associate_with_attribute(attribute)¶将此类型建立为给定映射描述符的突变侦听器。
sqlalchemy.ext.mutable.Mutable.
changed()¶每当发生更改事件时,子类应该调用此方法。
sqlalchemy.ext.mutable.Mutable.
classmethod coerce(key, value)¶inherited from the MutableBase.coerce()
method of MutableBase
给定一个值,将其强制为目标类型。
可以被自定义子类重写,以将传入数据强制为特定类型。
默认情况下,加薪 ValueError
.
根据父类的类型,在不同的方案中调用此方法 Mutable
或类型 MutableComposite
. 对于前者,在属性集操作和ORM加载操作期间都会调用它。对于后者,只在属性集操作期间调用; composite()
在加载操作期间构造句柄强制。
mixin,它定义了将SQLAlchemy“composite”对象上的更改事件透明传播到其所属父对象或父对象。
参见中的示例 确定复合材料的易变性 有关用法信息。
sqlalchemy.ext.mutable.MutableComposite.
changed()¶每当发生更改事件时,子类应该调用此方法。
实现的字典类型 Mutable
.
这个 MutableDict
对象实现一个字典,当字典的内容发生更改时(包括添加或删除值时),该字典将向基础映射发出更改事件。
注意 MutableDict
做 not 将可变跟踪应用于 价值观本身 在字典里。因此,对于跟踪深度更改到 递归的 字典结构,如JSON结构。要支持此用例,请构建 MutableDict
它对字典中的值进行适当的强制,使它们也“可变”,并向其父结构发出事件。
类签名
class sqlalchemy.ext.mutable.MutableDict
(sqlalchemy.ext.mutable.Mutable
, builtins.dict
)
sqlalchemy.ext.mutable.MutableDict.
clear() → None. Remove all items from D.¶sqlalchemy.ext.mutable.MutableDict.
classmethod coerce(key, value)¶将普通字典转换为此类的实例。
sqlalchemy.ext.mutable.MutableDict.
pop(k[, d]) → v, remove specified key and return the corresponding value.¶如果找不到键,则返回d(如果给定),否则将引发keyError
sqlalchemy.ext.mutable.MutableDict.
popitem() → (k, v), remove and return some (key, value) pair as a¶2元组;但如果d为空,则引发keyror。
sqlalchemy.ext.mutable.MutableDict.
setdefault(key, value)¶如果关键字不在字典中,则插入值为默认值的关键字。
如果键在字典中,则返回键的值,否则为默认值。
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]
实现的列表类型 Mutable
.
这个 MutableList
对象实现一个列表,该列表将在更改列表内容时(包括添加或删除值时)向基础映射发出更改事件。
注意 MutableList
做 not 将可变跟踪应用于 价值观本身 在列表中。因此,对于跟踪深度更改到 递归的 可变结构,如JSON结构。要支持此用例,请构建 MutableList
它对字典中的值进行适当的强制,使它们也“可变”,并向其父结构发出事件。
1.1 新版功能.
类签名
class sqlalchemy.ext.mutable.MutableList
(sqlalchemy.ext.mutable.Mutable
, builtins.list
)
sqlalchemy.ext.mutable.MutableList.
append(x)¶将对象追加到列表末尾。
sqlalchemy.ext.mutable.MutableList.
clear()¶从列表中删除所有项目。
sqlalchemy.ext.mutable.MutableList.
classmethod coerce(index, value)¶将普通列表转换为此类的实例。
sqlalchemy.ext.mutable.MutableList.
extend(x)¶通过从iterable附加元素来扩展列表。
sqlalchemy.ext.mutable.MutableList.
insert(i, x)¶在索引前插入对象。
sqlalchemy.ext.mutable.MutableList.
pop(*arg)¶移除并返回索引处的项(默认最后一个)。
如果列表为空或索引超出范围,则引发IndexError。
sqlalchemy.ext.mutable.MutableList.
remove(i)¶删除第一次出现的值。
如果值不存在,则引发ValueError。
sqlalchemy.ext.mutable.MutableList.
reverse()¶反向 就位 .
sqlalchemy.ext.mutable.MutableList.
sort(**kw)¶稳定排序 就位 .
实现的集合类型 Mutable
.
这个 MutableSet
对象实现一个集合,该集合将在更改集合内容时(包括添加或删除值时)向基础映射发出更改事件。
注意 MutableSet
做 not 将可变跟踪应用于 价值观本身 在布景里。因此,对于跟踪深度更改到 递归的 可变结构。要支持此用例,请构建 MutableSet
它对字典中的值进行适当的强制,使它们也“可变”,并向其父结构发出事件。
1.1 新版功能.
类签名
class sqlalchemy.ext.mutable.MutableSet
(sqlalchemy.ext.mutable.Mutable
, builtins.set
)
sqlalchemy.ext.mutable.MutableSet.
add(elem)¶向集合中添加元素。
如果元素已经存在,则此操作无效。
sqlalchemy.ext.mutable.MutableSet.
clear()¶删除此集合中的所有元素。
sqlalchemy.ext.mutable.MutableSet.
classmethod coerce(index, value)¶将普通集转换为此类的实例。
sqlalchemy.ext.mutable.MutableSet.
difference_update(*arg)¶从此集合中移除另一集合的所有元素。
sqlalchemy.ext.mutable.MutableSet.
discard(elem)¶如果元素是成员,则将其从集合中移除。
如果元素不是成员,则不执行任何操作。
sqlalchemy.ext.mutable.MutableSet.
intersection_update(*arg)¶用自身和另一个的交集更新集合。
sqlalchemy.ext.mutable.MutableSet.
pop(*arg)¶移除并返回任意集合元素。如果集合为空,则引发keyError。
sqlalchemy.ext.mutable.MutableSet.
remove(elem)¶从集合中移除元素;它必须是成员。
如果元素不是成员,则引发keyError。
sqlalchemy.ext.mutable.MutableSet.
symmetric_difference_update(*arg)¶使用自身和另一个的对称差异更新集。
sqlalchemy.ext.mutable.MutableSet.
update(*arg)¶使用自身和其他集合更新集合。
flambé! the dragon and The Alchemist image designs created and generously donated by Rotem Yaari.
Created using Sphinx 4.2.0.