diff --git a/docs/changelog.rst b/docs/changelog.rst index e3f3ecd1..d0af955e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,9 +5,13 @@ Changelog Changes in 0.9.X - DEV ====================== +<<<<<<< HEAD - OperationError: Shard Keys are immutable. Tried to update id even though the document is not yet saved #771 - with_limit_and_skip for count should default like in pymongo #759 - Fix storing value of precision attribute in DecimalField #787 +======= +- Set attribute to None does not work (at least for fields with default values) #734 +>>>>>>> bdbd495a9e778d12157b789a74e0e00a303b5efd - Querying by a field defined in a subclass raises InvalidQueryError #744 - Add Support For MongoDB 2.6.X's maxTimeMS #778 - abstract shouldn't be inherited in EmbeddedDocument # 789 diff --git a/mongoengine/base/fields.py b/mongoengine/base/fields.py index 5bb9c7ac..2747dde1 100644 --- a/mongoengine/base/fields.py +++ b/mongoengine/base/fields.py @@ -37,7 +37,7 @@ class BaseField(object): def __init__(self, db_field=None, name=None, required=False, default=None, unique=False, unique_with=None, primary_key=False, validation=None, choices=None, verbose_name=None, - help_text=None): + help_text=None, null=False): """ :param db_field: The database field to store this field in (defaults to the name of the field) @@ -60,6 +60,8 @@ class BaseField(object): model forms from the document model. :param help_text: (optional) The help text for this field and is often used when generating model forms from the document model. + :param null: (optional) Is the field value can be null. If no and there is a default value + then the default value is set """ self.db_field = (db_field or name) if not primary_key else '_id' @@ -75,6 +77,7 @@ class BaseField(object): self.choices = choices self.verbose_name = verbose_name self.help_text = help_text + self.null = null # Adjust the appropriate creation counter, and save our local copy. if self.db_field == '_id': @@ -100,10 +103,13 @@ class BaseField(object): # If setting to None and theres a default # Then set the value to the default value - if value is None and self.default is not None: - value = self.default - if callable(value): - value = value() + if value is None: + if self.null: + value = None + elif self.default is not None: + value = self.default + if callable(value): + value = value() if instance._initialised: try: diff --git a/tests/document/instance.py b/tests/document/instance.py index b7733548..5360ba36 100644 --- a/tests/document/instance.py +++ b/tests/document/instance.py @@ -57,7 +57,9 @@ class InstanceTest(unittest.TestCase): self.db.drop_collection(collection) def assertDbEqual(self, docs): - self.assertEqual(list(self.Person._get_collection().find().sort("id")), sorted(docs, key=lambda doc: doc["_id"])) + self.assertEqual( + list(self.Person._get_collection().find().sort("id")), + sorted(docs, key=lambda doc: doc["_id"])) def test_capped_collection(self): """Ensure that capped collections work properly. @@ -468,7 +470,7 @@ class InstanceTest(unittest.TestCase): f.reload() except Foo.DoesNotExist: pass - except Exception as ex: + except Exception: self.assertFalse("Threw wrong exception") def test_dictionary_access(self): @@ -2613,7 +2615,9 @@ class InstanceTest(unittest.TestCase): system.save() system = NodesSystem.objects.first() - self.assertEqual("UNDEFINED", system.nodes["node"].parameters["param"].macros["test"].value) + self.assertEqual( + "UNDEFINED", + system.nodes["node"].parameters["param"].macros["test"].value) def test_embedded_document_equality(self): @@ -2730,5 +2734,26 @@ class InstanceTest(unittest.TestCase): self.assertEquals(p.id, None) p.id = "12345" # in case it is not working: "OperationError: Shard Keys are immutable..." will be raised here + def test_null_field(self): + # 734 + class User(Document): + name = StringField() + height = IntField(default=184, null=True) + User.objects.delete() + u = User(name='user') + u.save() + u_from_db = User.objects.get(name='user') + u_from_db.height = None + u_from_db.save() + self.assertEquals(u_from_db.height, None) + + # 735 + User.objects.delete() + u = User(name='user') + u.save() + User.objects(name='user').update_one(set__height=None, upsert=True) + u_from_db = User.objects.get(name='user') + self.assertEquals(u_from_db.height, None) + if __name__ == '__main__': unittest.main()