支持跟踪对标量值的就地更改,这些更改将传播到所属父对象的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
, postgresql.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
类型提供类方法 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))
)
上面, 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
一步到位,使用 associate_with()
. 这和 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__
排除 _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()
事件处理程序可用于在可变标量发出更改事件时接收事件。当 attributes.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元类自动建立侦听器,以便使用 orm.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
对象。
sqlalchemy.ext.mutable.
MutableBase
¶公共基类到 Mutable
和 MutableComposite
.
_parents
¶父对象字典->父对象的属性名。
此属性是所谓的“memoized”属性。它用一个新的 weakref.WeakKeyDictionary
第一次访问它时,在随后访问时返回同一对象。
coerce
(key, value)¶给定一个值,将其强制为目标类型。
可以被自定义子类重写,以将传入数据强制为特定类型。
默认情况下,加薪 ValueError
.
根据父类的类型,在不同的方案中调用此方法 Mutable
或类型 MutableComposite
. 对于前者,在属性集操作和ORM加载操作期间都会调用它。对于后者,只在属性集操作期间调用; composite()
在加载操作期间构造句柄强制。
sqlalchemy.ext.mutable.
Mutable
¶基地: sqlalchemy.ext.mutable.MutableBase
定义将更改事件透明传播到父对象的mixin。
参见中的示例 建立标量列值的可变性 有关用法信息。
__eq__
¶继承 __eq__
属性 object
返回self==值。
__init__
¶继承 __init__
属性 object
初始化自身。请参阅帮助(键入(self))以获得准确的签名。
__le__
¶继承 __le__
属性 object
返回self<=value。
__lt__
¶继承 __lt__
属性 object
返回self<value。
__ne__
¶继承 __ne__
属性 object
回归自我!=值。
_get_listen_keys
(attribute)¶继承 _get_listen_keys()
方法 MutableBase
给定一个描述符属性,返回 set()
指示此属性状态更改的属性键。
这通常只是 set([attribute.key])
,但可以重写以提供其他键。例如 MutableComposite
使用与组成复合值的列关联的属性键扩充此集合。
如果截取 InstanceEvents.refresh()
和 InstanceEvents.refresh_flush()
事件,传递已刷新的属性名列表;将列表与此集合进行比较,以确定是否需要执行操作。
1.0.5 新版功能.
_listen_on_attribute
(attribute, coerce, parent_cls)¶继承 _listen_on_attribute()
方法 MutableBase
将此类型建立为给定映射描述符的突变侦听器。
_parents
¶继承 _parents
属性 MutableBase
父对象字典->父对象的属性名。
此属性是所谓的“memoized”属性。它用一个新的 weakref.WeakKeyDictionary
第一次访问它时,在随后访问时返回同一对象。
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()
对于应用程序的永久类型,而不是特殊类型,否则这将导致内存使用量的无限增长。
associate_with
(sqltype)¶将此包装与给定类型的所有未来映射列相关联。
这是一个调用 associate_with_attribute
自动地。
警告
通过这种方法建立的侦听器是 全球的 所有映射器,并且 not 垃圾收集。只使用 associate_with()
对于应用程序的永久类型,而不是特殊类型,否则这将导致内存使用量的无限增长。
associate_with_attribute
(attribute)¶将此类型建立为给定映射描述符的突变侦听器。
changed
()¶每当发生更改事件时,子类应该调用此方法。
coerce
(key, value)¶继承 coerce()
方法 MutableBase
给定一个值,将其强制为目标类型。
可以被自定义子类重写,以将传入数据强制为特定类型。
默认情况下,加薪 ValueError
.
根据父类的类型,在不同的方案中调用此方法 Mutable
或类型 MutableComposite
. 对于前者,在属性集操作和ORM加载操作期间都会调用它。对于后者,只在属性集操作期间调用; composite()
在加载操作期间构造句柄强制。
sqlalchemy.ext.mutable.
MutableComposite
¶基地: sqlalchemy.ext.mutable.MutableBase
mixin,它定义了将SQLAlchemy“composite”对象上的更改事件透明传播到其所属父对象或父对象。
参见中的示例 确定复合材料的易变性 有关用法信息。
changed
()¶每当发生更改事件时,子类应该调用此方法。
sqlalchemy.ext.mutable.
MutableDict
¶基地: sqlalchemy.ext.mutable.Mutable
, builtins.dict
实现的字典类型 Mutable
.
这个 MutableDict
对象实现一个字典,当字典的内容发生更改时(包括添加或删除值时),该字典将向基础映射发出更改事件。
注意 MutableDict
做 not 将可变跟踪应用于 价值观本身 在字典里。因此,对于跟踪深度更改到 递归的 字典结构,如JSON结构。要支持此用例,请构建 MutableDict
它对字典中的值进行适当的强制,使它们也“可变”,并向其父结构发出事件。
clear
() → None. Remove all items from D.¶coerce
(key, value)¶将普通字典转换为此类的实例。
pop
(k[, d]) → v, remove specified key and return the corresponding value.¶如果找不到键,则返回d(如果给定),否则将引发keyError
popitem
() → (k, v), remove and return some (key, value) pair as a¶2元组;但如果d为空,则引发keyror。
setdefault
(key, value)¶Insert key with a value of default if key is not in the dictionary.
Return the value for key if key is in the dictionary, else default.
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]
sqlalchemy.ext.mutable.
MutableList
¶基地: sqlalchemy.ext.mutable.Mutable
, builtins.list
实现的列表类型 Mutable
.
这个 MutableList
对象实现一个列表,该列表将在更改列表内容时(包括添加或删除值时)向基础映射发出更改事件。
注意 MutableList
做 not 将可变跟踪应用于 价值观本身 在列表中。因此,对于跟踪深度更改到 递归的 可变结构,如JSON结构。要支持此用例,请构建 MutableList
它对字典中的值进行适当的强制,使它们也“可变”,并向其父结构发出事件。
1.1 新版功能.
append
(x)¶Append object to the end of the list.
clear
()¶Remove all items from list.
coerce
(index, value)¶将普通列表转换为此类的实例。
extend
(x)¶Extend list by appending elements from the iterable.
insert
(i, x)¶Insert object before index.
pop
(*arg)¶Remove and return item at index (default last).
如果列表为空或索引超出范围,则引发IndexError。
remove
(i)¶Remove first occurrence of value.
如果值不存在,则引发ValueError。
reverse
()¶Reverse IN PLACE.
sort
()¶Stable sort IN PLACE.
sqlalchemy.ext.mutable.
MutableSet
¶基地: sqlalchemy.ext.mutable.Mutable
, builtins.set
实现的集合类型 Mutable
.
这个 MutableSet
对象实现一个集合,该集合将在更改集合内容时(包括添加或删除值时)向基础映射发出更改事件。
注意 MutableSet
做 not 将可变跟踪应用于 价值观本身 在布景里。因此,对于跟踪深度更改到 递归的 可变结构。要支持此用例,请构建 MutableSet
它对字典中的值进行适当的强制,使它们也“可变”,并向其父结构发出事件。
1.1 新版功能.
add
(elem)¶向集合中添加元素。
如果元素已经存在,则此操作无效。
clear
()¶删除此集合中的所有元素。
coerce
(index, value)¶将普通集转换为此类的实例。
difference_update
(*arg)¶从此集合中移除另一集合的所有元素。
discard
(elem)¶如果元素是成员,则将其从集合中移除。
如果元素不是成员,则不执行任何操作。
intersection_update
(*arg)¶用自身和另一个的交集更新集合。
pop
(*arg)¶移除并返回任意集合元素。如果集合为空,则引发keyError。
remove
(elem)¶从集合中移除元素;它必须是成员。
如果元素不是成员,则引发keyError。
symmetric_difference_update
(*arg)¶使用自身和另一个的对称差异更新集。
update
(*arg)¶使用自身和其他集合更新集合。