diff --git a/docs/changelog.rst b/docs/changelog.rst index 153bf42f..35b94b1e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,7 @@ Changelog Changes in 0.9.X - DEV ====================== +- Sparse fields #515 - write_concern not in params of Collection#remove #801 - Better BaseDocument equality check when not saved #798 - OperationError: Shard Keys are immutable. Tried to update id even though the document is not yet saved #771 diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index aea251e4..854ed6b4 100644 --- a/mongoengine/base/document.py +++ b/mongoengine/base/document.py @@ -786,10 +786,9 @@ class BaseDocument(object): """ unique_indexes = [] for field_name, field in cls._fields.items(): - sparse = False + sparse = field.sparse # Generate a list of indexes needed by uniqueness constraints if field.unique: - field.required = True unique_fields = [field.db_field] # Add any unique_with fields to the back of the index spec diff --git a/mongoengine/base/fields.py b/mongoengine/base/fields.py index 2747dde1..f86d4175 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, null=False): + help_text=None, null=False, sparse=False): """ :param db_field: The database field to store this field in (defaults to the name of the field) @@ -62,6 +62,8 @@ class BaseField(object): 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 + :param sparse: (optional) `sparse=True` combined with `unique=True` and `required=False` + means that uniqueness won't be enforced for `None` values """ self.db_field = (db_field or name) if not primary_key else '_id' @@ -78,6 +80,7 @@ class BaseField(object): self.verbose_name = verbose_name self.help_text = help_text self.null = null + self.sparse = sparse # Adjust the appropriate creation counter, and save our local copy. if self.db_field == '_id': diff --git a/tests/fields/fields.py b/tests/fields/fields.py index 26a30bfc..1079b235 100644 --- a/tests/fields/fields.py +++ b/tests/fields/fields.py @@ -3057,6 +3057,15 @@ class FieldTest(unittest.TestCase): self.assertEquals(Animal.objects(_cls__in=["Animal.Mammal.Dog", "Animal.Fish"]).count(), 2) self.assertEquals(Animal.objects(_cls__in=["Animal.Fish.Guppy"]).count(), 0) + def test_sparse_field(self): + class Doc(Document): + name = StringField(required=False, unique=True, sparse=True) + try: + Doc().save() + Doc().save() + except Exception: + self.fail() + if __name__ == '__main__': unittest.main()