Fix some issues related with db_field in constructor by removing field/db_field translation that shouldn't occur in constructor
This commit is contained in:
parent
eb56fb9bda
commit
8c3058d99b
@ -101,12 +101,13 @@ class BaseDocument:
|
|||||||
|
|
||||||
self._dynamic_fields = SON()
|
self._dynamic_fields = SON()
|
||||||
|
|
||||||
# Assign default values to the instance.
|
# Assign default values for fields
|
||||||
for key, field in self._fields.items():
|
# not set in the constructor
|
||||||
if self._db_field_map.get(key, key) in values:
|
for field_name in self._fields:
|
||||||
|
if field_name in values:
|
||||||
continue
|
continue
|
||||||
value = getattr(self, key, None)
|
value = getattr(self, field_name, None)
|
||||||
setattr(self, key, value)
|
setattr(self, field_name, value)
|
||||||
|
|
||||||
if "_cls" not in values:
|
if "_cls" not in values:
|
||||||
self._cls = self._class_name
|
self._cls = self._class_name
|
||||||
@ -115,7 +116,6 @@ class BaseDocument:
|
|||||||
dynamic_data = {}
|
dynamic_data = {}
|
||||||
FileField = _import_class("FileField")
|
FileField = _import_class("FileField")
|
||||||
for key, value in values.items():
|
for key, value in values.items():
|
||||||
key = self._reverse_db_field_map.get(key, key)
|
|
||||||
field = self._fields.get(key)
|
field = self._fields.get(key)
|
||||||
if field or key in ("id", "pk", "_cls"):
|
if field or key in ("id", "pk", "_cls"):
|
||||||
if __auto_convert and value is not None:
|
if __auto_convert and value is not None:
|
||||||
@ -750,7 +750,8 @@ class BaseDocument:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _from_son(cls, son, _auto_dereference=True, created=False):
|
def _from_son(cls, son, _auto_dereference=True, created=False):
|
||||||
"""Create an instance of a Document (subclass) from a PyMongo SON."""
|
"""Create an instance of a Document (subclass) from a PyMongo SON (dict)
|
||||||
|
"""
|
||||||
if son and not isinstance(son, dict):
|
if son and not isinstance(son, dict):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"The source SON object needs to be of type 'dict' but a '%s' was found"
|
"The source SON object needs to be of type 'dict' but a '%s' was found"
|
||||||
@ -763,6 +764,8 @@ class BaseDocument:
|
|||||||
|
|
||||||
# Convert SON to a data dict, making sure each key is a string and
|
# Convert SON to a data dict, making sure each key is a string and
|
||||||
# corresponds to the right db field.
|
# corresponds to the right db field.
|
||||||
|
# This is needed as _from_son is currently called both from BaseDocument.__init__
|
||||||
|
# and from EmbeddedDocumentField.to_python
|
||||||
data = {}
|
data = {}
|
||||||
for key, value in son.items():
|
for key, value in son.items():
|
||||||
key = str(key)
|
key = str(key)
|
||||||
|
@ -3822,5 +3822,97 @@ class ObjectKeyTestCase(MongoDBTestCase):
|
|||||||
assert book._object_key == {"pk": book.pk, "author__name": "Author"}
|
assert book._object_key == {"pk": book.pk, "author__name": "Author"}
|
||||||
|
|
||||||
|
|
||||||
|
class DBFieldMappingTest(MongoDBTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
class Fields(object):
|
||||||
|
w1 = BooleanField(db_field="w2")
|
||||||
|
|
||||||
|
x1 = BooleanField(db_field="x2")
|
||||||
|
x2 = BooleanField(db_field="x3")
|
||||||
|
|
||||||
|
y1 = BooleanField(db_field="y0")
|
||||||
|
y2 = BooleanField(db_field="y1")
|
||||||
|
|
||||||
|
z1 = BooleanField(db_field="z2")
|
||||||
|
z2 = BooleanField(db_field="z1")
|
||||||
|
|
||||||
|
class Doc(Fields, Document):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class DynDoc(Fields, DynamicDocument):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.Doc = Doc
|
||||||
|
self.DynDoc = DynDoc
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
for collection in self.db.collection_names():
|
||||||
|
if "system." in collection:
|
||||||
|
continue
|
||||||
|
self.db.drop_collection(collection)
|
||||||
|
|
||||||
|
def test_setting_fields_in_constructor_of_strict_doc_uses_model_names(self):
|
||||||
|
doc = self.Doc(z1=True, z2=False)
|
||||||
|
assert doc.z1 is True
|
||||||
|
assert doc.z2 is False
|
||||||
|
|
||||||
|
def test_setting_fields_in_constructor_of_dyn_doc_uses_model_names(self):
|
||||||
|
doc = self.DynDoc(z1=True, z2=False)
|
||||||
|
assert doc.z1 is True
|
||||||
|
assert doc.z2 is False
|
||||||
|
|
||||||
|
def test_setting_unknown_field_in_constructor_of_dyn_doc_does_not_overwrite_model_fields(
|
||||||
|
self,
|
||||||
|
):
|
||||||
|
doc = self.DynDoc(w2=True)
|
||||||
|
assert doc.w1 is None
|
||||||
|
assert doc.w2 is True
|
||||||
|
|
||||||
|
def test_unknown_fields_of_strict_doc_do_not_overwrite_dbfields_1(self):
|
||||||
|
doc = self.Doc()
|
||||||
|
doc.w2 = True
|
||||||
|
doc.x3 = True
|
||||||
|
doc.y0 = True
|
||||||
|
doc.save()
|
||||||
|
reloaded = self.Doc.objects.get(id=doc.id)
|
||||||
|
assert reloaded.w1 is None
|
||||||
|
assert reloaded.x1 is None
|
||||||
|
assert reloaded.x2 is None
|
||||||
|
assert reloaded.y1 is None
|
||||||
|
assert reloaded.y2 is None
|
||||||
|
|
||||||
|
def test_dbfields_are_loaded_to_the_right_modelfield_for_strict_doc_2(self):
|
||||||
|
doc = self.Doc()
|
||||||
|
doc.x2 = True
|
||||||
|
doc.y2 = True
|
||||||
|
doc.z2 = True
|
||||||
|
doc.save()
|
||||||
|
reloaded = self.Doc.objects.get(id=doc.id)
|
||||||
|
assert (
|
||||||
|
reloaded.x1,
|
||||||
|
reloaded.x2,
|
||||||
|
reloaded.y1,
|
||||||
|
reloaded.y2,
|
||||||
|
reloaded.z1,
|
||||||
|
reloaded.z2,
|
||||||
|
) == (doc.x1, doc.x2, doc.y1, doc.y2, doc.z1, doc.z2)
|
||||||
|
|
||||||
|
def test_dbfields_are_loaded_to_the_right_modelfield_for_dyn_doc_2(self):
|
||||||
|
doc = self.DynDoc()
|
||||||
|
doc.x2 = True
|
||||||
|
doc.y2 = True
|
||||||
|
doc.z2 = True
|
||||||
|
doc.save()
|
||||||
|
reloaded = self.DynDoc.objects.get(id=doc.id)
|
||||||
|
assert (
|
||||||
|
reloaded.x1,
|
||||||
|
reloaded.x2,
|
||||||
|
reloaded.y1,
|
||||||
|
reloaded.y2,
|
||||||
|
reloaded.z1,
|
||||||
|
reloaded.z2,
|
||||||
|
) == (doc.x1, doc.x2, doc.y1, doc.y2, doc.z1, doc.z2)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -2272,6 +2272,13 @@ class TestField(MongoDBTestCase):
|
|||||||
with pytest.raises(FieldDoesNotExist):
|
with pytest.raises(FieldDoesNotExist):
|
||||||
Doc(bar="test")
|
Doc(bar="test")
|
||||||
|
|
||||||
|
def test_undefined_field_works_no_confusion_with_db_field(self):
|
||||||
|
class Doc(Document):
|
||||||
|
foo = StringField(db_field="bar")
|
||||||
|
|
||||||
|
with pytest.raises(FieldDoesNotExist):
|
||||||
|
Doc(bar="test")
|
||||||
|
|
||||||
|
|
||||||
class TestEmbeddedDocumentListField(MongoDBTestCase):
|
class TestEmbeddedDocumentListField(MongoDBTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user