Django

Code

Ticket #6108 (new)

Opened 2 years ago

Last modified 4 months ago

send all_objects_to_be_deleted in the pre_delete signal

Reported by: Gábor Farkas <gabor@nekomancer.net> Assigned to: nobody
Milestone: Component: Core framework
Version: SVN Keywords:
Cc: carljm, hv@tbz-pariv.de, plandry@provplan.org Triage Stage: Design decision needed
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 1

Description

when django deletes an object, it also deletes all related objects.

it would be great to send the list of "to be deleted objects" in the pre_delete signal, because then a developer could implement in his application things like only-delete-object-when-there-are-no-related-objects (by raising an Exception in the listener-function), etc.

it can be implemented by an one-line change in db/models/query.py (patch attached).

Attachments

pre_delete.patch (1.8 kB) - added by Gábor Farkas <gabor@nekomancer.net> on 12/02/07 15:45:30.

Change History

12/02/07 15:45:30 changed by Gábor Farkas <gabor@nekomancer.net>

  • attachment pre_delete.patch added.

12/02/07 19:05:09 changed by Simon G <dev@simon.net.nz>

  • needs_better_patch changed.
  • has_patch set to 1.
  • stage changed from Unreviewed to Ready for checkin.
  • needs_tests changed.
  • needs_docs changed.

12/04/07 13:52:09 changed by jacob

  • needs_better_patch set to 1.
  • stage changed from Ready for checkin to Design decision needed.

This unfortunately needs to be more complicated to handle all the use cases for this feature. We need the following features:

  • Listeners should be able to modify the list of to-be-deleted objects. I think that'll work with your patch, but a test is needed to make sure that happens.
  • Because each doomed object gets a signal sent listener code might end up running multiple times. So we might need to figure out which objects have already been signaled. We could avoid a duplicate list (and the duplicate memory that would require) with some other lightweight structure -- perhaps the list of objects-to-delete could be a list of (object, has_been_notified)?
  • Another option to avoid duplicated callbacks would be an initial bulk-pre-delete signal (that is, use the same signal but with instance=None and instance_list=list_of_doomed_objects.
  • We also need to verify that we can in fact implement ON DELETE CASCADE-like behavior with this. If not, it's something of a worthless addition.

12/04/07 14:34:42 changed by Gábor Farkas <gabor@nekomancer.net>

could you please elaborate on the"ON DELETE CASCADE-like behavior" part?

what kind of behaviors do you imagine here?

as i see, the current django-delete behavior is basically on-delete-cascade... so did you mean maybe to implement "ON DELETE SET NULL" and other such behaviors? or "filtered cascading"?

from what i see here, most of the situations where you want to delete less objects, than what django wants do delete, are implementable.

in short:

i will write the testcases, if you tell me what kind of situations i need to test :)

also, from the 2 possibilities to avoid duplicate-callbacks, i think the initial bulk-pre-delete signal one is the best.

08/19/08 17:02:50 changed by mh

honestly, _please_ implement this (by merging this patch or calling the default Manager delete method, I won't be picky about this)

with the current code base (unless there is some magic hidden in db/models/query.py ...) i found no possibility to prevent a object from being deleted - apart from creating an ON DELETE - Trigger in the DB that silently prevents the deletion of a record

this is, however, not possible in all environments (if all databases were full-featured, this whole hack would not need to exist ...), and leads to unnecessary separation/fragmentation of logic. so please fix this issue one way or another

08/21/08 09:10:03 changed by gabor

the following (ugly) code should work:

overload the delete() method of the object like this:

    def delete(self):
        from django.utils.datastructures import SortedDict
        s = SortedDict()
        self._collect_sub_objects(s)
        #here s will contain all the objects that are planned to be deleted
        if s.items() == [(type(u), { u.pk : u })]:
            super(YourModel, self).delete()
        else:
            raise Exception("related objects found")

the code is untested, but i'm doing something very similar and it works. if you want to make it 100% safe, you have to run it in a serializable-transaction unfortunately :( otherwise it could happen, that the call to _collect_sub_objects returns that all is fine, but while the code proceeds to delete-the-object, some other process already inserted new "dependent" objects, and those will get deleted.

yes, it contains a call to a private undocumented method. no, afaik no other way exists.

02/16/09 03:10:37 changed by gabor

if anyone is planning to use above-mentioned code-snippet, please note, that for django-1.0 it has to be changed slightly:

def delete(self):
    from django.db.models.query import CollectedObjects
    s = CollectedObjects()
    self._collect_sub_objects(s)
    #here s will contain all the objects that are planned to be deleted
    if s.items() == [(type(u), { u.pk : u })]:
        super(YourModel, self).delete()
    else:
        raise Exception("related objects found")

yes, this is a good example of why not to use private undocumented methods (because they might change between versions...)

02/16/09 08:12:59 changed by carljm

  • cc set to carljm.

06/26/09 03:12:35 changed by guettli

  • cc changed from carljm to carljm, hv@tbz-pariv.de.

06/26/09 03:15:49 changed by guettli

Related: #7539 Add ON DELETE and ON UPDATE support to Django

11/17/09 09:08:53 changed by anonymous

  • cc changed from carljm, hv@tbz-pariv.de to carljm, hv@tbz-pariv.de, plandry@provplan.org.

Add/Change #6108 (send all_objects_to_be_deleted in the pre_delete signal)




Change Properties
Action