Repository: MongoEngine/mongoengine

Issue:
DynamicDocument doesn't parse known fields to python
We are using this package it is great.
Actually, we validate(`schema validation`) the document even if it is a `DynamicDocument` (**the document should always have all the known fields and the right type**). And when we change the document to `DynamicDocument` we have an `OperationError` after investigating we noticed that in a `DynamicDocument` the known fields are not parsed into python when the document is initialized. By **known fields** I am meaning that the **declared field in the document**
 
For example 

```python
>>> import mongoengine
>>> class ProductDocument(mongoengine.Document):
...      title = mongoengine.StringField()
...      price = mongoengine.FloatField()
... 
>>> p = ProductDocument(title='Blabla', price='12.5')
>>> p.price
12.5
>>> type(p.price)
<class 'float'>

>>> class ProductDynamicDocument(mongoengine.DynamicDocument):
...      title = mongoengine.StringField()
...      price = mongoengine.FloatField()

>>> p_dynamic.price
'12.5'
>>> type(p_dynamic.price)
<class 'str'>
```

It should be good to parse value to python if the field is declared on the document even if the document is a `DynamicDocument`


Discussion:
Good catch, I'm looking into it now

Resolving patch:
diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py
--- a/mongoengine/base/document.py
+++ b/mongoengine/base/document.py
@@ -117,25 +117,22 @@ def __init__(self, *args, **values):
         if "_cls" not in values:
             self._cls = self._class_name
 
-        # Set passed values after initialisation
-        if self._dynamic:
-            dynamic_data = {}
-            for key, value in values.items():
-                if key in self._fields or key == "_id":
-                    setattr(self, key, value)
-                else:
+        # Set actual values
+        dynamic_data = {}
+        FileField = _import_class("FileField")
+        for key, value in values.items():
+            key = self._reverse_db_field_map.get(key, key)
+            field = self._fields.get(key)
+            if field or key in ("id", "pk", "_cls"):
+                if __auto_convert and value is not None:
+                    if field and not isinstance(field, FileField):
+                        value = field.to_python(value)
+                setattr(self, key, value)
+            else:
+                if self._dynamic:
                     dynamic_data[key] = value
-        else:
-            FileField = _import_class("FileField")
-            for key, value in values.items():
-                key = self._reverse_db_field_map.get(key, key)
-                if key in self._fields or key in ("id", "pk", "_cls"):
-                    if __auto_convert and value is not None:
-                        field = self._fields.get(key)
-                        if field and not isinstance(field, FileField):
-                            value = field.to_python(value)
-                    setattr(self, key, value)
                 else:
+                    # For strict Document
                     self._data[key] = value
 
         # Set any get_<field>_display methods


Test patch:
diff --git a/tests/document/test_dynamic.py b/tests/document/test_dynamic.py
--- a/tests/document/test_dynamic.py
+++ b/tests/document/test_dynamic.py
@@ -37,6 +37,19 @@ def test_simple_dynamic_document(self):
         # Confirm no changes to self.Person
         assert not hasattr(self.Person, "age")
 
+    def test_dynamic_document_parse_values_in_constructor_like_document_do(self):
+        class ProductDynamicDocument(DynamicDocument):
+            title = StringField()
+            price = FloatField()
+
+        class ProductDocument(Document):
+            title = StringField()
+            price = FloatField()
+
+        product = ProductDocument(title="Blabla", price="12.5")
+        dyn_product = ProductDynamicDocument(title="Blabla", price="12.5")
+        assert product.price == dyn_product.price == 12.5
+
     def test_change_scope_of_variable(self):
         """Test changing the scope of a dynamic field has no adverse effects"""
         p = self.Person()