The basic problem you're up against here is that a model's delete()
method is not necessarily going to be run when it is deleted indirectly.
Django tries to optimise deletes and updates so that they are single (or
minimal numbers of) SQL queries, which means not calling a method on
each instance, but, rather, doing a bulk delete at the database level.
This is documented, although it's one of those things that doesn't
immediately jump out:
http://docs.djangoproject.com/en/dev/topics/db/queries/#topics-db-queries-delete
(The queryset and model documentation is a bit all over the place at the
moment -- we need a few more links between places.)
I think that's really going to be the showstopper here. You can't hope
to control the bulk delete (which includes related object deletion) at
that sort of level.
Regards,
Malcolm
For a model such as Book, you could iterate through
Book._meta.get_all_field_names(), call Book._meta.get_field_by_name()
for each name and look at the "direct" component of the returned result
to see which are the reverse relations. Those are then the things
pointing to your model.
There are docstrings on get_field_by_name() and get_all_field_names() in
django/db/models/options.py that will help you out there.
> ?
>
> One other thought - let me know if you see any issue with this. Let's
> say I just never want my reader objects to get deleted based on
> related object deletions. I think I can just define
>
> class Reader:
> def delete(self):
> pass
>
> Then delete will do nothing and if I really want to delete my reader I
> can call some other method that I define that then calls super(Reader,
> self).delete().
That will work for a direct call. Isn't there going to be some related
object deletion cases that still won't be caught, though? Isn't this
exactly the case that you were examining in the initial post?
> The actual object that is my "reader" (the above example was used just
> for simplicity) is really my UserProfile object. I would think that
> this is a common problem
Boy do I hate that phrase! For every possible programming problem, there
is certainly a non-zero number of people who want some particular piece
of behaviour. But there's pretty much no way to measure "common" unless
you have a total userbase of, like, 17 people. At some point, everything
is both common to some group and pretty much irrelevant to the majority.
> - not wanting one's userProfiles to ever get
> deleted.
Ultimately, Python is a language for consenting adults. If you don't
want the object to be deleted, don't call delete on things involving
that object.
It's understood that delete behaviour is something that has a few
different options. Coming up with a save API for controlling those which
doesn't leak SQL-juice all over the Python level code or make things
horribly an untenably inefficient, has been something we've been
wrestling with for quite a while. So far without really having a great
solution that we're happy committing. This isn't for want of actual hard
thinking on the problem by a number of people.
For now, it's a matter of being careful and trusting your users to not
do crazy stuff.
It's not optimal, but it is survivable.
Regards,
Malcolm