diff --git a/AUTHORS b/AUTHORS index 860a7890..2d1a073a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -122,3 +122,4 @@ that much better: * Sergey Nikitin * psychogenic * Stefan Wójcik + * dimonb diff --git a/docs/changelog.rst b/docs/changelog.rst index aa37af9b..737f997c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,7 @@ Changelog Changes in 0.7.X ================= +- Fixed reloading on sharded documents (hmarr/mongoengine#569) - Added NotUniqueError for duplicate keys (MongoEngine/mongoengine#62) - Added custom collection / sequence naming for SequenceFields (MongoEngine/mongoengine#92) - Fixed UnboundLocalError in composite index with pk field (MongoEngine/mongoengine#88) diff --git a/mongoengine/base.py b/mongoengine/base.py index 05a08e59..82f79d3b 100644 --- a/mongoengine/base.py +++ b/mongoengine/base.py @@ -949,8 +949,10 @@ class BaseDocument(object): self._data[name] = value if hasattr(self, '_changed_fields'): self._mark_as_changed(name) + if (self._is_document and not self._created and - name in self._meta.get('shard_key', tuple())): + name in self._meta.get('shard_key', tuple()) and + self._data.get(name) != value): OperationError = _import_class('OperationError') msg = "Shard Keys are immutable. Tried to update %s" % name raise OperationError(msg) diff --git a/mongoengine/document.py b/mongoengine/document.py index 1691df93..9d528cbc 100644 --- a/mongoengine/document.py +++ b/mongoengine/document.py @@ -295,6 +295,16 @@ class Document(BaseDocument): ref.save(**kwargs) ref._changed_fields = [] + @property + def _object_key(self): + """Dict to identify object in collection + """ + select_dict = {'pk': self.pk} + shard_key = self.__class__._meta.get('shard_key', tuple()) + for k in shard_key: + select_dict[k] = getattr(self, k) + return select_dict + def update(self, **kwargs): """Performs an update on the :class:`~mongoengine.Document` A convenience wrapper to :meth:`~mongoengine.QuerySet.update`. @@ -306,11 +316,7 @@ class Document(BaseDocument): raise OperationError('attempt to update a document not yet saved') # Need to add shard key to query, or you get an error - select_dict = {'pk': self.pk} - shard_key = self.__class__._meta.get('shard_key', tuple()) - for k in shard_key: - select_dict[k] = getattr(self, k) - return self.__class__.objects(**select_dict).update_one(**kwargs) + return self.__class__.objects(**self._object_key).update_one(**kwargs) def delete(self, safe=False): """Delete the :class:`~mongoengine.Document` from the database. This @@ -321,7 +327,7 @@ class Document(BaseDocument): signals.pre_delete.send(self.__class__, document=self) try: - self.__class__.objects(pk=self.pk).delete(safe=safe) + self.__class__.objects(**self._object_key).delete(safe=safe) except pymongo.errors.OperationFailure, err: message = u'Could not delete document (%s)' % err.message raise OperationError(message) diff --git a/tests/test_document.py b/tests/test_document.py index 350defd7..821637ea 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -1258,6 +1258,17 @@ class DocumentTest(unittest.TestCase): self.assertEqual(person.name, "Mr Test User") self.assertEqual(person.age, 21) + def test_reload_sharded(self): + class Animal(Document): + superphylum = StringField() + meta = {'shard_key': ('superphylum',)} + + Animal.drop_collection() + doc = Animal(superphylum = 'Deuterostomia') + doc.save() + doc.reload() + Animal.drop_collection() + def test_reload_referencing(self): """Ensures reloading updates weakrefs correctly """