refs #709, added support to disable auto_sync

This commit is contained in:
Wilson Júnior 2014-07-25 18:12:26 -03:00
parent 15bbf26b93
commit 6c0112c2be
3 changed files with 101 additions and 7 deletions

View File

@ -31,7 +31,7 @@ class DocumentMetaclass(type):
attrs['_is_document'] = attrs.get('_is_document', False)
attrs['_cached_reference_fields'] = []
# EmbeddedDocuments could have meta data for inheritance
if 'meta' in attrs:
attrs['_meta'] = attrs.pop('meta')
@ -181,9 +181,12 @@ class DocumentMetaclass(type):
if not f.document_type:
raise InvalidDocumentError(
"Document is not avaiable to sync")
if f.auto_sync:
f.start_listener()
f.document_type._cached_reference_fields.append(f)
if isinstance(f, ComplexBaseField) and hasattr(f, 'field'):
delete_rule = getattr(f.field,
'reverse_delete_rule',

View File

@ -989,10 +989,11 @@ class CachedReferenceField(BaseField):
.. 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.
: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 \
not issubclass(document_type, (Document, basestring)):
@ -1000,10 +1001,33 @@ class CachedReferenceField(BaseField):
self.error('Argument to CachedReferenceField constructor must be a'
' document class or a string')
self.auto_sync = auto_sync
self.document_type_obj = document_type
self.fields = fields
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):
"""Convert a MongoDB-compatible type to a Python type.
"""
@ -1088,7 +1112,6 @@ class CachedReferenceField(BaseField):
def sync_all(self):
update_key = 'set__%s' % self.name
errors = []
for doc in self.document_type.objects:
filter_kwargs = {}
@ -1097,8 +1120,6 @@ class CachedReferenceField(BaseField):
update_kwargs = {}
update_kwargs[update_key] = doc
errors.append((filter_kwargs, update_kwargs))
self.owner_document.objects(
**filter_kwargs).update(**update_kwargs)

View File

@ -1608,6 +1608,76 @@ class FieldTest(unittest.TestCase):
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):
class Owner(EmbeddedDocument):
TPS = (