django-resurrectable Summary ------- This is a basic implementation of "pseudo-deleting" model instances, so they can be un-deleted later. Terminology ----------- This document uses the terms "undeleted" and "non-deleted" interchangeably, since an object that has been deleted and then undeleted is indistinguishable from one that has never been deleted at all. Installation ------------ 1) Put resurrectable/ somewhere in your PYTHONPATH. 2) Add resurrectable to the INSTALLED_APPS list in your settings.py file. 3) Subclass resurrectable.models.Resurrectable for any model that you want to be resurrectable. 4) (optional) Define a method called get_resurrectable_children() on your resurrectable model classes. This method should return an iterable of strings mapping to related objects that will be (un)deleted with this object. (See note below about the current abilities of cascading deletes). Example: from django.db import models from resurrectable.models import Resurrectable class Choice(models.Model): answer = models.CharField(max_length=80) poll = models.ForeignKey(Poll, related_name='choices') class Poll(Resurrectable, models.Model): question = models.CharField(max_length=80) def get_resurrectable_children(self): return ['choices'] 5) Somehow add the 'deleted' date_time field to tables in your database that represent resurrectable models (e.g. drop the model tables and run manage.py syncdb, use a schema migration tool, sling some SQL, etc.). (Un)deleting Objects -------------------- * Deleting: To pseudo-delete an object, just call its delete() method as usual. * Undeleting: Call the object's undelete() method. Both methods support a 'cascade' keyword argument that defaults to True. Calling either method with cascade=False will skip the (un)deleting of objects specified by the object's resurrectable_children Meta attribute. Querying for (Un)deleted Objects -------------------------------- To get all objects (deleted and undeleted), simply query as you normally would: Foo.objects.all() To get only objects that are deleted, call the deleted() method on a queryset: Foo.objects.all().deleted() To get only objects that have not been deleted, call the not_deleted() method: Foo.objects.all().not_deleted() A shortcut function (resurrectable.shortcuts.get_nondeleted_or_404()) exists for easily getting a particular object while ensuring that it hasn't been deleted. This function takes the same arguments as and behaves the same as django.shortcuts.get_object_or_404, except if the object is deleted, Http404 is raised. You can determine if an object has been deleted by calling object.is_deleted(). Admin ----- ModelAdmin subclasses may also subclass resurrectable.admin.ResurrectableAdmin to inherit two boolean methods: * is_deleted(self, object) * not_deleted(self, object) These may be used anywhere a ModelAdmin method is allowed (e.g. list_display). Notes ----- * If you want to use a custom manager for any model subclassing Resurrectable, it should subclass ResurrectableManager (otherwise the queryset methods discussed above will not be available filtered out). * Admin strings are currently English only. * Cascading doesn't work yet.