views:

347

answers:

3

Instead of deleting records in my Django application, I want to just mark them as "deleted" and have them hidden from my active queries. My main reason to do this is to give the user an undelete option in case they accidentally delete a record (these records may also be needed for certain backend audit tracking.)

There are a lot of foreign key relationships, so when I mark a record as deleted I'd have to "Casade" this delete flag to those records as well. What tools, existing projects, or methods should I use to do this?

+2  A: 

Nice question, I've been wondering how to efficiently do this myself.

I am not sure if this will do the trick, but django-reversion seems to do what you want, although you probably want to examine to see how it achieves this goal, as there are some inefficient ways to do it.

Another thought would be to have the dreaded boolean flag on your Models and then creating a custom manager that automatically adds the filter in, although this wouldn't work for searches across different Models. Yet another solution suggested here is to have duplicate models of everything, which seems like overkill, but may work for you. The comments there also discuss different options.

I will add that for the most part I don't consider any of these solutions worth the hassle; I usually just suck it up and filter my searches on the boolean flag. It avoids many issues that can come up if you try to get too clever. It is a pain and not very DRY, of course. A reasonable solution would be a mixture of the Custom manager while being aware of its limitations if you try searching a related model through it.

Paolo Bergantino
+1 - I'd never heard of this project... the rollback feature alone is tantalizing if true!
Jarret Hardie
django-reversion is cool, but it's absolute overkill in this case, don't you think? We're talking about reversing a boolean state, not rolling back to one of multiple stored versions of an object.
ozan
@ozan: "I will add that for the most part I don't consider any of these solutions worth the hassle."
Paolo Bergantino
+2  A: 

I think using a boolean 'is_active' flag is fine - you don't need to cascade the flag to related entries at the db level, you just need to keep referring to the status of the parent. This is what happens with contrib.auth's User model, remember - marking a user as not is_active doesn't prompt django to go through related models and magically try to deactivate records, rather you just keep checking the is_active attribute of the user corresponding to the related item.

For instance if each user has many bookmarks, and you don't want an inactive user's bookmarks to be visible, just ensure that bookmark.user.is_active is true. There's unlikely to be a need for an is_active flag on the bookmark itself.

ozan
+3  A: 

Django offers out of the box the exact mechanism you are looking for.

You can change the manager that is used for access through related objects. If you new custom manager filters the object on a boolean field, the object flagged inactive won't show up in your requests.

See here for more details : http://docs.djangoproject.com/en/dev/topics/db/managers/#using-managers-for-related-object-access

madewulf