We use model subclasses in our application and we have come across a situation where Django gets confused when it tries to delete a model object and its related items. Our model contains a class that refers to a base/subclass model with a foreign key, and the base/subclass model in refers back to this class in turn.
The example below should make this clearer. Let's say we are interested in celebrities, which are categorised into subclasses including the TV Chef celebrity subclass. Celebrities can have multiple fans, but a celebrity can have only one "greatest" fan.
class Celebrity(models.Model):
name = models.CharField("Name", max_length=20)
greatest_fan = models.ForeignKey("Fan", null=True, unique=True)
class TvChef(Celebrity):
pass
class Fan(models.Model):
fan_of = models.ForeignKey(Celebrity)
With these model relationships, Django will be unable to delete the TvChef subclass if it has multiple related Fans. If you run the test program below, it will try to nullify a non-existent column in the TvChef database table.
from subclass_deletion.models import *
c1 = Celebrity.objects.create(name="Madonna")
c2 = Celebrity.objects.create(name="The Queen")
c3 = TvChef.objects.create(name="Huey")
f1 = Fan.objects.create(fan_of=c3)
f2 = Fan.objects.create(fan_of=c3)
c3.greatest_fan = f1
c3.save()
# You cannot delete the TvChef subclass, it fails with the error:
# OperationalError: no such column: greatest_fan_id
# This error occurs when it tries to run the SQL (sqlite3):
# UPDATE "subclass_deletion_tvchef" SET "greatest_fan_id" = NULL WHERE "celebrity_ptr_id" IN (3)
c3.delete()
The attached patch performs a sanity-check before Django attempts to clear related fields, and will avoid doing so if it cannot find the expected column name in the class that is the "to" destination.