diff --git a/mongoengine/base/fields.py b/mongoengine/base/fields.py index aa16804e..08fbc9b7 100644 --- a/mongoengine/base/fields.py +++ b/mongoengine/base/fields.py @@ -83,6 +83,7 @@ class BaseField(object): self.help_text = help_text self.null = null self.sparse = sparse + self._owner_document = None # Adjust the appropriate creation counter, and save our local copy. if self.db_field == '_id': @@ -189,6 +190,17 @@ class BaseField(object): self.validate(value, **kwargs) + @property + def owner_document(self): + return self._owner_document + + def _set_owner_document(self, owner_document): + self._owner_document = owner_document + + @owner_document.setter + def owner_document(self, owner_document): + self._set_owner_document(owner_document) + class ComplexBaseField(BaseField): @@ -398,11 +410,6 @@ class ComplexBaseField(BaseField): self.field.owner_document = owner_document self._owner_document = owner_document - def _get_owner_document(self, owner_document): - self._owner_document = owner_document - - owner_document = property(_get_owner_document, _set_owner_document) - class ObjectIdField(BaseField): diff --git a/mongoengine/base/metaclasses.py b/mongoengine/base/metaclasses.py index 48da84f4..7a104da9 100644 --- a/mongoengine/base/metaclasses.py +++ b/mongoengine/base/metaclasses.py @@ -176,7 +176,8 @@ class DocumentMetaclass(type): # Handle delete rules for field in new_class._fields.itervalues(): f = field - f.owner_document = new_class + if f.owner_document is None: + f.owner_document = new_class delete_rule = getattr(f, 'reverse_delete_rule', DO_NOTHING) if isinstance(f, CachedReferenceField): diff --git a/tests/document/validation.py b/tests/document/validation.py index 573c2e57..ba03366e 100644 --- a/tests/document/validation.py +++ b/tests/document/validation.py @@ -165,6 +165,53 @@ class ValidatorErrorTest(unittest.TestCase): self.assertRaises(ValidationError, lambda: d2.validate()) + def test_parent_reference_in_child_document(self): + """ + Test to ensure a ReferenceField can store a reference to a parent + class when inherited. Issue #954. + """ + class Parent(Document): + meta = {'allow_inheritance': True} + reference = ReferenceField('self') + + class Child(Parent): + pass + + parent = Parent() + parent.save() + + child = Child(reference=parent) + + # Saving child should not raise a ValidationError + try: + child.save() + except ValidationError as e: + self.fail("ValidationError raised: %s" % e.message) + + def test_parent_reference_set_as_attribute_in_child_document(self): + """ + Test to ensure a ReferenceField can store a reference to a parent + class when inherited and when set via attribute. Issue #954. + """ + class Parent(Document): + meta = {'allow_inheritance': True} + reference = ReferenceField('self') + + class Child(Parent): + pass + + parent = Parent() + parent.save() + + child = Child() + child.reference = parent + + # Saving the child should not raise a ValidationError + try: + child.save() + except ValidationError as e: + self.fail("ValidationError raised: %s" % e.message) + if __name__ == '__main__': unittest.main()