Added lock when calling doc.Delete() for when signals have no sender (#350)

This commit is contained in:
Ross Lawley 2013-06-04 16:35:25 +00:00
parent d47134bbf1
commit eeb5a83e98
4 changed files with 16 additions and 75 deletions

View File

@ -5,6 +5,7 @@ Changelog
Changes in 0.8.2 Changes in 0.8.2
================ ================
- Added lock when calling doc.Delete() for when signals have no sender (#350)
- Reload forces read preference to be PRIMARY (#355) - Reload forces read preference to be PRIMARY (#355)
- Querysets are now lest restrictive when querying duplicate fields (#332, #333) - Querysets are now lest restrictive when querying duplicate fields (#332, #333)
- FileField now honouring db_alias (#341) - FileField now honouring db_alias (#341)

View File

@ -347,11 +347,10 @@ class Document(BaseDocument):
signals.pre_delete.send(self.__class__, document=self) signals.pre_delete.send(self.__class__, document=self)
try: try:
self._qs.filter(**self._object_key).delete(write_concern=write_concern) self._qs.filter(**self._object_key).delete(write_concern=write_concern, _from_doc_delete=True)
except pymongo.errors.OperationFailure, err: except pymongo.errors.OperationFailure, err:
message = u'Could not delete document (%s)' % err.message message = u'Could not delete document (%s)' % err.message
raise OperationError(message) raise OperationError(message)
signals.post_delete.send(self.__class__, document=self) signals.post_delete.send(self.__class__, document=self)
def switch_db(self, db_alias): def switch_db(self, db_alias):

View File

@ -407,7 +407,7 @@ class QuerySet(object):
self._len = count self._len = count
return count return count
def delete(self, write_concern=None): def delete(self, write_concern=None, _from_doc_delete=False):
"""Delete the documents matched by the query. """Delete the documents matched by the query.
:param write_concern: Extra keyword arguments are passed down which :param write_concern: Extra keyword arguments are passed down which
@ -416,20 +416,25 @@ class QuerySet(object):
``save(..., write_concern={w: 2, fsync: True}, ...)`` will ``save(..., write_concern={w: 2, fsync: True}, ...)`` will
wait until at least two servers have recorded the write and wait until at least two servers have recorded the write and
will force an fsync on the primary server. will force an fsync on the primary server.
:param _from_doc_delete: True when called from document delete therefore
signals will have been triggered so don't loop.
""" """
queryset = self.clone() queryset = self.clone()
doc = queryset._document doc = queryset._document
if not write_concern:
write_concern = {}
# Handle deletes where skips or limits have been applied or
# there is an untriggered delete signal
has_delete_signal = signals.signals_available and ( has_delete_signal = signals.signals_available and (
signals.pre_delete.has_receivers_for(self._document) or signals.pre_delete.has_receivers_for(self._document) or
signals.post_delete.has_receivers_for(self._document)) signals.post_delete.has_receivers_for(self._document))
if not write_concern: call_document_delete = (queryset._skip or queryset._limit or
write_concern = {} has_delete_signal) and not _from_doc_delete
# Handle deletes where skips or limits have been applied or has a if call_document_delete:
# delete signal
if queryset._skip or queryset._limit or has_delete_signal:
for doc in queryset: for doc in queryset:
doc.delete(write_concern=write_concern) doc.delete(write_concern=write_concern)
return return

View File

@ -41,7 +41,7 @@ class SignalTests(unittest.TestCase):
@classmethod @classmethod
def pre_save(cls, sender, document, **kwargs): def pre_save(cls, sender, document, **kwargs):
signal_output.append('pre_save signal,, %s' % document) signal_output.append('pre_save signal, %s' % document)
@classmethod @classmethod
def pre_save_post_validation(cls, sender, document, **kwargs): def pre_save_post_validation(cls, sender, document, **kwargs):
@ -83,54 +83,6 @@ class SignalTests(unittest.TestCase):
self.Author = Author self.Author = Author
Author.drop_collection() Author.drop_collection()
class Another(Document):
name = StringField()
def __unicode__(self):
return self.name
@classmethod
def pre_init(cls, sender, document, **kwargs):
signal_output.append('pre_init Another signal, %s' % cls.__name__)
signal_output.append(str(kwargs['values']))
@classmethod
def post_init(cls, sender, document, **kwargs):
signal_output.append('post_init Another signal, %s' % document)
@classmethod
def pre_save(cls, sender, document, **kwargs):
signal_output.append('pre_save Another signal, %s' % document)
@classmethod
def pre_save_post_validation(cls, sender, document, **kwargs):
signal_output.append('pre_save_post_validation Another signal, %s' % document)
if 'created' in kwargs:
if kwargs['created']:
signal_output.append('Is created')
else:
signal_output.append('Is updated')
@classmethod
def post_save(cls, sender, document, **kwargs):
signal_output.append('post_save Another signal, %s' % document)
if 'created' in kwargs:
if kwargs['created']:
signal_output.append('Is created')
else:
signal_output.append('Is updated')
@classmethod
def pre_delete(cls, sender, document, **kwargs):
signal_output.append('pre_delete Another signal, %s' % document)
@classmethod
def post_delete(cls, sender, document, **kwargs):
signal_output.append('post_delete Another signal, %s' % document)
self.Another = Another
Another.drop_collection()
class ExplicitId(Document): class ExplicitId(Document):
id = IntField(primary_key=True) id = IntField(primary_key=True)
@ -169,14 +121,6 @@ class SignalTests(unittest.TestCase):
signals.pre_bulk_insert.connect(Author.pre_bulk_insert, sender=Author) signals.pre_bulk_insert.connect(Author.pre_bulk_insert, sender=Author)
signals.post_bulk_insert.connect(Author.post_bulk_insert, sender=Author) signals.post_bulk_insert.connect(Author.post_bulk_insert, sender=Author)
signals.pre_init.connect(Another.pre_init, sender=Another)
signals.post_init.connect(Another.post_init, sender=Another)
signals.pre_save.connect(Another.pre_save, sender=Another)
signals.pre_save_post_validation.connect(Another.pre_save_post_validation, sender=Another)
signals.post_save.connect(Another.post_save, sender=Another)
signals.pre_delete.connect(Another.pre_delete, sender=Another)
signals.post_delete.connect(Another.post_delete, sender=Another)
signals.post_save.connect(ExplicitId.post_save, sender=ExplicitId) signals.post_save.connect(ExplicitId.post_save, sender=ExplicitId)
def tearDown(self): def tearDown(self):
@ -190,14 +134,6 @@ class SignalTests(unittest.TestCase):
signals.pre_bulk_insert.disconnect(self.Author.pre_bulk_insert) signals.pre_bulk_insert.disconnect(self.Author.pre_bulk_insert)
signals.post_bulk_insert.disconnect(self.Author.post_bulk_insert) signals.post_bulk_insert.disconnect(self.Author.post_bulk_insert)
signals.pre_init.disconnect(self.Another.pre_init)
signals.post_init.disconnect(self.Another.post_init)
signals.post_delete.disconnect(self.Another.post_delete)
signals.pre_delete.disconnect(self.Another.pre_delete)
signals.post_save.disconnect(self.Another.post_save)
signals.pre_save_post_validation.disconnect(self.Another.pre_save_post_validation)
signals.pre_save.disconnect(self.Another.pre_save)
signals.post_save.disconnect(self.ExplicitId.post_save) signals.post_save.disconnect(self.ExplicitId.post_save)
# Check that all our signals got disconnected properly. # Check that all our signals got disconnected properly.
@ -239,7 +175,7 @@ class SignalTests(unittest.TestCase):
a1 = self.Author(name='Bill Shakespeare') a1 = self.Author(name='Bill Shakespeare')
self.assertEqual(self.get_signal_output(a1.save), [ self.assertEqual(self.get_signal_output(a1.save), [
"pre_save signal,, Bill Shakespeare", "pre_save signal, Bill Shakespeare",
"pre_save_post_validation signal, Bill Shakespeare", "pre_save_post_validation signal, Bill Shakespeare",
"Is created", "Is created",
"post_save signal, Bill Shakespeare", "post_save signal, Bill Shakespeare",
@ -249,7 +185,7 @@ class SignalTests(unittest.TestCase):
a1.reload() a1.reload()
a1.name = 'William Shakespeare' a1.name = 'William Shakespeare'
self.assertEqual(self.get_signal_output(a1.save), [ self.assertEqual(self.get_signal_output(a1.save), [
"pre_save signal,, William Shakespeare", "pre_save signal, William Shakespeare",
"pre_save_post_validation signal, William Shakespeare", "pre_save_post_validation signal, William Shakespeare",
"Is updated", "Is updated",
"post_save signal, William Shakespeare", "post_save signal, William Shakespeare",