Skip to content
This repository has been archived by the owner on Mar 29, 2021. It is now read-only.
/ cascade Public archive

Test Django project used to explore transaction handling in model deletions.

License

Notifications You must be signed in to change notification settings

yunojuno-archive/cascade

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Django Cascade Delete

Test Django project used to explore transaction handling in model deletions.

There has been some discussion within the YunoJuno development team about the use of signals within the Django model ORM framework, whether it's good practice, or even safe to rely on, when processing side-effects.

The primary use case is the cascading deletion of models, and how this is handled internally by the Django ORM. An initial investigation of the Django source suggested that when calling the delete method of a top-level object (one that is a parent of a child object), the child's delete method is never called, but its pre_delete and post_delete signals are:

def delete(self):
    [...]
    # send pre_delete signals
    for model, obj in self.instances_with_model():
        [...]
        signals.pre_delete.send([...])

    [...]

    # delete instances
    for model, instances in six.iteritems(self.data):
        query = sql.DeleteQuery(model)
        [...]
        for obj in instances:
            signals.post_delete.send([...])
    [...]

The open question is where to put code that needs to run when an object is deleted, but not directly (i.e. as part of a cascade). For instance, if you need to delete other objects, that are not part of the implicit cascade delete, should you put that code into the child model's delete method, or in a signal receiver?

This project is a test app used to explore this in more detail.

It consists of a simple Django app with two models - Parent, and Child. The Child model has a ForeignKey relationship to the Parent model. There are pre_delete and post_delete signal receive handlers for both models.

In both pre_delete handlers, if the name attribute of the model is "Job" an exception is raised. This is used to force the rollback of any containing transactions, so that, in theory, if you call parent.delete() on a Parent object that has a Child object with name=="Job", the entire transaction will rollback to its original state.

In addition to the test coverage, each method contains verbose logging that can be used to highlight the methods being run at any time.

The suggested test verbosity is '2', e.g.

$ python manage.py test --verbosity=2

##Spoiler

This is the output from calling delete on an object with three child objects:

>>> parent = Parent(name=u"Fred")
>>> parent.save()
>>> Child(name=u"Bob", parent=parent).save()
>>> Child(name=u"Gob", parent=parent).save()
>>> Child(name=u"Lob", parent=parent).save()
>>> parent.delete()
DEBUG Enter Parent.delete() method.
DEBUG Deleting Child: Bob.  # pre_delete signal
DEBUG Deleting Child: Gob.
DEBUG Deleting Child: Lob.
DEBUG Deleting Parent: Fred.
DEBUG Deleted Child: Lob.  # post_delete signal
DEBUG Deleted Child: Gob.
DEBUG Deleted Child: Bob.
DEBUG Deleted Parent: Fred.
DEBUG Exit Parent.delete() method.

This confirms the observations from the source code above:

  • Child objects' pre_delete signals are fired
  • The Child objects' delete methods are not called
  • Child objects' post_delete signales are fired
  • Parent signals are fired after related child signals

##Django Source

The Django source is freely available on Github, and the relevant code for the ORM cascade delete is in the django.db.models.deletion.Collector class.

##Prerequisites

There is a requirements.txt file that contains the project dependencies.

NB psycopg2 is only required when running the tests agains a Postgres database - which is recommended because of the transactional support (given that that is the whole point of the project). However, you can run the tests against SQLite if you wish (database settings just need to the uncommented).

About

Test Django project used to explore transaction handling in model deletions.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published