diff --git a/AUTHORS b/AUTHORS index 880dfad1..e8a43dac 100644 --- a/AUTHORS +++ b/AUTHORS @@ -248,4 +248,5 @@ that much better: * Andy Yankovsky (https://github.com/werat) * Bastien Gérard (https://github.com/bagerard) * Trevor Hall (https://github.com/tjhall13) - * Gleb Voropaev (https://github.com/buggyspace) \ No newline at end of file + * Gleb Voropaev (https://github.com/buggyspace) + * Paulo Amaral (https://github.com/pauloAmaral) diff --git a/docs/changelog.rst b/docs/changelog.rst index 9a606812..42a0ab14 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,7 @@ Changelog Development =========== +- Generate Unique Indices for SortedListField and EmbeddedDocumentListFields #2020 - (Fill this out as you fix issues and develop your features). Changes in 0.17.0 diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index 8587f17f..4cf34b4f 100644 --- a/mongoengine/base/document.py +++ b/mongoengine/base/document.py @@ -883,7 +883,8 @@ class BaseDocument(object): index = {'fields': fields, 'unique': True, 'sparse': sparse} unique_indexes.append(index) - if field.__class__.__name__ == 'ListField': + if field.__class__.__name__ in {'EmbeddedDocumentListField', + 'ListField', 'SortedListField'}: field = field.field # Grab any embedded document field unique indexes diff --git a/tests/document/indexes.py b/tests/document/indexes.py index abd349f3..b63faa9d 100644 --- a/tests/document/indexes.py +++ b/tests/document/indexes.py @@ -708,6 +708,77 @@ class IndexesTest(unittest.TestCase): self.assertRaises(NotUniqueError, post2.save) + def test_unique_embedded_document_in_sorted_list(self): + """ + Ensure that the uniqueness constraints are applied to fields in + embedded documents, even when the embedded documents in a sorted list + field. + """ + class SubDocument(EmbeddedDocument): + year = IntField() + slug = StringField(unique=True) + + class BlogPost(Document): + title = StringField() + subs = SortedListField(EmbeddedDocumentField(SubDocument), + ordering='year') + + BlogPost.drop_collection() + + post1 = BlogPost( + title='test1', subs=[ + SubDocument(year=2009, slug='conflict'), + SubDocument(year=2009, slug='conflict') + ] + ) + post1.save() + + # confirm that the unique index is created + indexes = BlogPost._get_collection().index_information() + self.assertIn('subs.slug_1', indexes) + self.assertTrue(indexes['subs.slug_1']['unique']) + + post2 = BlogPost( + title='test2', subs=[SubDocument(year=2014, slug='conflict')] + ) + + self.assertRaises(NotUniqueError, post2.save) + + def test_unique_embedded_document_in_embedded_document_list(self): + """ + Ensure that the uniqueness constraints are applied to fields in + embedded documents, even when the embedded documents in an embedded + list field. + """ + class SubDocument(EmbeddedDocument): + year = IntField() + slug = StringField(unique=True) + + class BlogPost(Document): + title = StringField() + subs = EmbeddedDocumentListField(SubDocument) + + BlogPost.drop_collection() + + post1 = BlogPost( + title='test1', subs=[ + SubDocument(year=2009, slug='conflict'), + SubDocument(year=2009, slug='conflict') + ] + ) + post1.save() + + # confirm that the unique index is created + indexes = BlogPost._get_collection().index_information() + self.assertIn('subs.slug_1', indexes) + self.assertTrue(indexes['subs.slug_1']['unique']) + + post2 = BlogPost( + title='test2', subs=[SubDocument(year=2014, slug='conflict')] + ) + + self.assertRaises(NotUniqueError, post2.save) + def test_unique_with_embedded_document_and_embedded_unique(self): """Ensure that uniqueness constraints are applied to fields on embedded documents. And work with unique_with as well.