Repository: MongoEngine/mongoengine

Issue:
ReferenceField('self') attribute of a subclass document can't hold an instance of parent class document
```
class Parent(Document):
    link = ReferenceField('self')

class Child(Parent):
   pass

parent = Parent()
parent.save()
child = Child()
child.link = parent
# Below line throws ValidationError: ValidationError (A ReferenceField only accepts DBRef or documents)
child.save()
```

Is this an expected behaviour?

Using MongoDB 3.0.2 with MongoEngine 0.9.0 and PyMongo 2.7.2.

Add test to demonstrate issue #954
<!-- Reviewable:start -->

[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/mongoengine/mongoengine/955)

<!-- Reviewable:end -->



Discussion:
That seems wrong to me.
Can you submit this test case in form of a PR please?



Resolving patch:
diff --git a/mongoengine/base/fields.py b/mongoengine/base/fields.py
--- a/mongoengine/base/fields.py
+++ b/mongoengine/base/fields.py
@@ -83,6 +83,7 @@ def __init__(self, db_field=None, name=None, required=False, default=None,
         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 @@ def _validate(self, value, **kwargs):
 
         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 @@ def _set_owner_document(self, owner_document):
             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
--- a/mongoengine/base/metaclasses.py
+++ b/mongoengine/base/metaclasses.py
@@ -176,7 +176,8 @@ def __new__(cls, name, bases, attrs):
         # 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):
 


Test patch:
diff --git a/tests/document/validation.py b/tests/document/validation.py
--- a/tests/document/validation.py
+++ b/tests/document/validation.py
@@ -165,6 +165,53 @@ class Doc(Document):
 
         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()