Repository: MongoEngine/mongoengine

Issue:
OperationError: Shard Keys are immutable. Tried to update id even though the document is not yet saved
Inherited from Person in tests/document/instance.py:

```
class MyPerson(self.Person):
    meta = dict(shard_key=["id"])
p = MyPerson._from_son({"name": "name", "age": 27})
self.assertEquals(p.id, None)
p.id = "12345"
```

This exception is thrown:

```
Error
Traceback (most recent call last):
  File "/mongoengine/tests/document/instance.py", line 2651, in test_change_id
    p.id = "12345"
  File "/mongoengine/mongoengine/base/document.py", line 161, in __setattr__
    raise OperationError(msg)
OperationError: Shard Keys are immutable. Tried to update id
```

It can be claimed that _from_son is a private method and shouldn't be used by users
But from_json is not and it calls _from_son...



Discussion:

Resolving patch:
diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py
--- a/mongoengine/base/document.py
+++ b/mongoengine/base/document.py
@@ -386,9 +386,9 @@ def to_json(self, *args, **kwargs):
         return json_util.dumps(self.to_mongo(use_db_field),  *args, **kwargs)
 
     @classmethod
-    def from_json(cls, json_data):
+    def from_json(cls, json_data, created=False):
         """Converts json data to an unsaved document instance"""
-        return cls._from_son(json_util.loads(json_data))
+        return cls._from_son(json_util.loads(json_data), created=created)
 
     def __expand_dynamic_values(self, name, value):
         """expand any dynamic values to their correct types / values"""
@@ -617,7 +617,7 @@ def _get_collection_name(cls):
         return cls._meta.get('collection', None)
 
     @classmethod
-    def _from_son(cls, son, _auto_dereference=True, only_fields=[]):
+    def _from_son(cls, son, _auto_dereference=True, only_fields=[], created=False):
         """Create an instance of a Document (subclass) from a PyMongo SON.
         """
 
@@ -667,7 +667,7 @@ def _from_son(cls, son, _auto_dereference=True, only_fields=[]):
         if cls.STRICT:
             data = dict((k, v)
                         for k, v in data.iteritems() if k in cls._fields)
-        obj = cls(__auto_convert=False, _created=False, __only_fields=only_fields, **data)
+        obj = cls(__auto_convert=False, _created=created, __only_fields=only_fields, **data)
         obj._changed_fields = changed_fields
         if not _auto_dereference:
             obj._fields = fields


Test patch:
diff --git a/tests/document/instance.py b/tests/document/instance.py
--- a/tests/document/instance.py
+++ b/tests/document/instance.py
@@ -2719,5 +2719,16 @@ class Person(Document):
         self.assertEquals(p4.height, 189)
         self.assertEquals(Person.objects(height=189).count(), 1)
 
+    def test_from_son(self):
+        # 771
+        class MyPerson(self.Person):
+            meta = dict(shard_key=["id"])
+        p = MyPerson.from_json('{"name": "name", "age": 27}', created=True)
+        self.assertEquals(p.id, None)
+        p.id = "12345"  # in case it is not working: "OperationError: Shard Keys are immutable..." will be raised here
+        p = MyPerson._from_son({"name": "name", "age": 27}, created=True)
+        self.assertEquals(p.id, None)
+        p.id = "12345"  # in case it is not working: "OperationError: Shard Keys are immutable..." will be raised here
+
 if __name__ == '__main__':
     unittest.main()