refs #709, added support to disable auto_sync
This commit is contained in:
parent
15bbf26b93
commit
6c0112c2be
@ -31,7 +31,7 @@ class DocumentMetaclass(type):
|
|||||||
|
|
||||||
attrs['_is_document'] = attrs.get('_is_document', False)
|
attrs['_is_document'] = attrs.get('_is_document', False)
|
||||||
attrs['_cached_reference_fields'] = []
|
attrs['_cached_reference_fields'] = []
|
||||||
|
|
||||||
# EmbeddedDocuments could have meta data for inheritance
|
# EmbeddedDocuments could have meta data for inheritance
|
||||||
if 'meta' in attrs:
|
if 'meta' in attrs:
|
||||||
attrs['_meta'] = attrs.pop('meta')
|
attrs['_meta'] = attrs.pop('meta')
|
||||||
@ -181,9 +181,12 @@ class DocumentMetaclass(type):
|
|||||||
if not f.document_type:
|
if not f.document_type:
|
||||||
raise InvalidDocumentError(
|
raise InvalidDocumentError(
|
||||||
"Document is not avaiable to sync")
|
"Document is not avaiable to sync")
|
||||||
|
|
||||||
|
if f.auto_sync:
|
||||||
|
f.start_listener()
|
||||||
|
|
||||||
f.document_type._cached_reference_fields.append(f)
|
f.document_type._cached_reference_fields.append(f)
|
||||||
|
|
||||||
if isinstance(f, ComplexBaseField) and hasattr(f, 'field'):
|
if isinstance(f, ComplexBaseField) and hasattr(f, 'field'):
|
||||||
delete_rule = getattr(f.field,
|
delete_rule = getattr(f.field,
|
||||||
'reverse_delete_rule',
|
'reverse_delete_rule',
|
||||||
|
@ -989,10 +989,11 @@ class CachedReferenceField(BaseField):
|
|||||||
.. versionadded:: 0.9
|
.. versionadded:: 0.9
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, document_type, fields=[], **kwargs):
|
def __init__(self, document_type, fields=[], auto_sync=True, **kwargs):
|
||||||
"""Initialises the Cached Reference Field.
|
"""Initialises the Cached Reference Field.
|
||||||
|
|
||||||
:param fields: A list of fields to be cached in document
|
:param fields: A list of fields to be cached in document
|
||||||
|
:param auto_sync: if True documents are auto updated.
|
||||||
"""
|
"""
|
||||||
if not isinstance(document_type, basestring) and \
|
if not isinstance(document_type, basestring) and \
|
||||||
not issubclass(document_type, (Document, basestring)):
|
not issubclass(document_type, (Document, basestring)):
|
||||||
@ -1000,10 +1001,33 @@ class CachedReferenceField(BaseField):
|
|||||||
self.error('Argument to CachedReferenceField constructor must be a'
|
self.error('Argument to CachedReferenceField constructor must be a'
|
||||||
' document class or a string')
|
' document class or a string')
|
||||||
|
|
||||||
|
self.auto_sync = auto_sync
|
||||||
self.document_type_obj = document_type
|
self.document_type_obj = document_type
|
||||||
self.fields = fields
|
self.fields = fields
|
||||||
super(CachedReferenceField, self).__init__(**kwargs)
|
super(CachedReferenceField, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def start_listener(self):
|
||||||
|
"""
|
||||||
|
Start listener for document alterations, and update relacted docs
|
||||||
|
"""
|
||||||
|
from mongoengine import signals
|
||||||
|
signals.post_save.connect(self.on_document_pre_save,
|
||||||
|
sender=self.document_type)
|
||||||
|
|
||||||
|
def on_document_pre_save(self, sender, document, created, **kwargs):
|
||||||
|
if not created:
|
||||||
|
update_kwargs = {
|
||||||
|
'set__%s__%s' % (self.name, k): v
|
||||||
|
for k, v in document._delta()[0].items()
|
||||||
|
if k in self.fields}
|
||||||
|
|
||||||
|
if update_kwargs:
|
||||||
|
filter_kwargs = {}
|
||||||
|
filter_kwargs[self.name] = document
|
||||||
|
|
||||||
|
self.owner_document.objects(
|
||||||
|
**filter_kwargs).update(**update_kwargs)
|
||||||
|
|
||||||
def to_python(self, value):
|
def to_python(self, value):
|
||||||
"""Convert a MongoDB-compatible type to a Python type.
|
"""Convert a MongoDB-compatible type to a Python type.
|
||||||
"""
|
"""
|
||||||
@ -1088,7 +1112,6 @@ class CachedReferenceField(BaseField):
|
|||||||
|
|
||||||
def sync_all(self):
|
def sync_all(self):
|
||||||
update_key = 'set__%s' % self.name
|
update_key = 'set__%s' % self.name
|
||||||
errors = []
|
|
||||||
|
|
||||||
for doc in self.document_type.objects:
|
for doc in self.document_type.objects:
|
||||||
filter_kwargs = {}
|
filter_kwargs = {}
|
||||||
@ -1097,8 +1120,6 @@ class CachedReferenceField(BaseField):
|
|||||||
update_kwargs = {}
|
update_kwargs = {}
|
||||||
update_kwargs[update_key] = doc
|
update_kwargs[update_key] = doc
|
||||||
|
|
||||||
errors.append((filter_kwargs, update_kwargs))
|
|
||||||
|
|
||||||
self.owner_document.objects(
|
self.owner_document.objects(
|
||||||
**filter_kwargs).update(**update_kwargs)
|
**filter_kwargs).update(**update_kwargs)
|
||||||
|
|
||||||
|
@ -1608,6 +1608,76 @@ class FieldTest(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertRaises(InvalidDocumentError, build)
|
self.assertRaises(InvalidDocumentError, build)
|
||||||
|
|
||||||
|
def test_cached_reference_auto_sync(self):
|
||||||
|
class Person(Document):
|
||||||
|
TYPES = (
|
||||||
|
('pf', "PF"),
|
||||||
|
('pj', "PJ")
|
||||||
|
)
|
||||||
|
name = StringField()
|
||||||
|
tp = StringField(
|
||||||
|
choices=TYPES
|
||||||
|
)
|
||||||
|
|
||||||
|
father = CachedReferenceField('self', fields=('tp',))
|
||||||
|
|
||||||
|
Person.drop_collection()
|
||||||
|
|
||||||
|
a1 = Person(name="Wilson Father", tp="pj")
|
||||||
|
a1.save()
|
||||||
|
|
||||||
|
a2 = Person(name='Wilson Junior', tp='pf', father=a1)
|
||||||
|
a2.save()
|
||||||
|
|
||||||
|
a1.tp = 'pf'
|
||||||
|
a1.save()
|
||||||
|
|
||||||
|
a2.reload()
|
||||||
|
self.assertEqual(dict(a2.to_mongo()), {
|
||||||
|
'_id': a2.pk,
|
||||||
|
'name': 'Wilson Junior',
|
||||||
|
'tp': 'pf',
|
||||||
|
'father': {
|
||||||
|
'_id': a1.pk,
|
||||||
|
'tp': 'pf'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_cached_reference_auto_sync_disabled(self):
|
||||||
|
class Persone(Document):
|
||||||
|
TYPES = (
|
||||||
|
('pf', "PF"),
|
||||||
|
('pj', "PJ")
|
||||||
|
)
|
||||||
|
name = StringField()
|
||||||
|
tp = StringField(
|
||||||
|
choices=TYPES
|
||||||
|
)
|
||||||
|
|
||||||
|
father = CachedReferenceField(
|
||||||
|
'self', fields=('tp',), auto_sync=False)
|
||||||
|
|
||||||
|
Persone.drop_collection()
|
||||||
|
|
||||||
|
a1 = Persone(name="Wilson Father", tp="pj")
|
||||||
|
a1.save()
|
||||||
|
|
||||||
|
a2 = Persone(name='Wilson Junior', tp='pf', father=a1)
|
||||||
|
a2.save()
|
||||||
|
|
||||||
|
a1.tp = 'pf'
|
||||||
|
a1.save()
|
||||||
|
|
||||||
|
self.assertEqual(Persone.objects._collection.find_one({'_id': a2.pk}), {
|
||||||
|
'_id': a2.pk,
|
||||||
|
'name': 'Wilson Junior',
|
||||||
|
'tp': 'pf',
|
||||||
|
'father': {
|
||||||
|
'_id': a1.pk,
|
||||||
|
'tp': 'pj'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
def test_cached_reference_embedded_fields(self):
|
def test_cached_reference_embedded_fields(self):
|
||||||
class Owner(EmbeddedDocument):
|
class Owner(EmbeddedDocument):
|
||||||
TPS = (
|
TPS = (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user