diff --git a/docs/apireference.rst b/docs/apireference.rst index 6c42d40a..9b4f2c66 100644 --- a/docs/apireference.rst +++ b/docs/apireference.rst @@ -84,6 +84,7 @@ Fields .. autoclass:: mongoengine.fields.MapField .. autoclass:: mongoengine.fields.ReferenceField .. autoclass:: mongoengine.fields.GenericReferenceField +.. autoclass:: mongoengine.fields.CachedReferenceField .. autoclass:: mongoengine.fields.BinaryField .. autoclass:: mongoengine.fields.FileField .. autoclass:: mongoengine.fields.ImageField diff --git a/mongoengine/fields.py b/mongoengine/fields.py index a6ffb94f..7bbc221a 100644 --- a/mongoengine/fields.py +++ b/mongoengine/fields.py @@ -985,7 +985,7 @@ class ReferenceField(BaseField): class CachedReferenceField(BaseField): """ - A referencefield with cache fields support + A referencefield with cache fields to porpuse pseudo-joins .. versionadded:: 0.9 """ @@ -1007,9 +1007,6 @@ class CachedReferenceField(BaseField): 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) @@ -1029,8 +1026,6 @@ class CachedReferenceField(BaseField): **filter_kwargs).update(**update_kwargs) def to_python(self, value): - """Convert a MongoDB-compatible type to a Python type. - """ if isinstance(value, dict): collection = self.document_type._get_collection_name() value = DBRef( @@ -1048,8 +1043,6 @@ class CachedReferenceField(BaseField): return self.document_type_obj def __get__(self, instance, owner): - """Descriptor to allow lazy dereferencing. - """ if instance is None: # Document class being used rather than a document object return self @@ -1079,9 +1072,9 @@ class CachedReferenceField(BaseField): else: self.error('Only accept a document object') - value = { - "_id": id_field.to_mongo(id_) - } + value = SON(( + ("_id", id_field.to_mongo(id_)), + )) value.update(dict(document.to_mongo(fields=self.fields))) return value @@ -1111,6 +1104,10 @@ class CachedReferenceField(BaseField): return self.document_type._fields.get(member_name) def sync_all(self): + """ + Sync all cached fields on demand. + Caution: this operation may be slower. + """ update_key = 'set__%s' % self.name for doc in self.document_type.objects: diff --git a/tests/fields/fields.py b/tests/fields/fields.py index 77490ddb..342a13b3 100644 --- a/tests/fields/fields.py +++ b/tests/fields/fields.py @@ -1546,6 +1546,91 @@ class FieldTest(unittest.TestCase): self.assertEqual(ocorrence.person, "teste") self.assertTrue(isinstance(ocorrence.animal, Animal)) + def test_cached_reference_field_decimal(self): + class PersonAuto(Document): + name = StringField() + salary = DecimalField() + + class SocialTest(Document): + group = StringField() + person = CachedReferenceField( + PersonAuto, + fields=('salary',)) + + PersonAuto.drop_collection() + SocialTest.drop_collection() + + p = PersonAuto(name="Alberto", salary=Decimal('7000.00')) + p.save() + + s = SocialTest(group="dev", person=p) + s.save() + + self.assertEqual( + SocialTest.objects._collection.find_one({'person.salary': 7000.00}), { + '_id': s.pk, + 'group': s.group, + 'person': { + '_id': p.pk, + 'salary': p.salary + } + }) + + def test_cached_reference_field_reference(self): + class Group(Document): + name = StringField() + + class Person(Document): + name = StringField() + group = ReferenceField(Group) + + class SocialData(Document): + obs = StringField() + tags = ListField( + StringField()) + person = CachedReferenceField( + Person, + fields=('group',)) + + Group.drop_collection() + Person.drop_collection() + SocialData.drop_collection() + + g1 = Group(name='dev') + g1.save() + + g2 = Group(name="designers") + g2.save() + + p1 = Person(name="Alberto", group=g1) + p1.save() + + p2 = Person(name="Andre", group=g1) + p2.save() + + p3 = Person(name="Afro design", group=g2) + p3.save() + + s1 = SocialData(obs="testing 123", person=p1, tags=['tag1', 'tag2']) + s1.save() + + s2 = SocialData(obs="testing 321", person=p3, tags=['tag3', 'tag4']) + s2.save() + + self.assertEqual(SocialData.objects._collection.find_one( + {'tags': 'tag2'}), { + '_id': s1.pk, + 'obs': 'testing 123', + 'tags': ['tag1', 'tag2'], + 'person': { + '_id': p1.pk, + 'group': g1.pk + } + }) + + self.assertEqual(SocialData.objects(person__group=g2).count(), 1) + self.assertEqual(SocialData.objects(person__group=g2).first(), s2) + def test_cached_reference_field_update_all(self): class Person(Document): TYPES = (