[Fixed]-How to delete one-to-one relating models cascading in django?

12👍

You attach post_delete signal to your model so it is called upon deletion of an instance of Book or Newspaper:

from django.db.models.signals import post_delete
from django.dispatch import receiver

@receiver(post_delete, sender=Book)
def auto_delete_publish_info_with_book(sender, instance, **kwargs):
    instance.info.delete()

@receiver(post_delete, sender=Newspaper)
def auto_delete_publish_info_with_newpaper(sender, instance, **kwargs):
    instance.info.delete()

7👍

Another straight forward solution by overriding save and delete method:

Comparing to the answer of @ozgur, I found using signal to cascading the delete action has the same effect as deleting by overriding the Model.delete() method, and also we might auto create the attached PublishInfo:

class Book(models.Model):

    info = models.OneToOneField(
        PublishInfo, on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if not self.info:
            self.info = Publish.objects.create()
            super().save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        super().delete(*args, **kwargs)
        if self.info:
            self.info.delete()

More structured and reusable solution:

So, soon I realized the three listing field and methods are obviously redundant on each Model which was attaching the PublishInfo models as a field.

So, why don’t we use inheritance?

class PublishInfoAttachedModel(models.Model):

    info = models.OneToOneField(
        PublishInfo, related_name='$(class)s',
        on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if not self.info:
            self.info = Publish.objects.create()
            super().save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        super().delete(*args, **kwargs)
        if self.info:
            self.info.delete()

    class Meta:
        abstract = True

Remember to add abstract = True in its meta class.

So, now we are free to add PublishInfo in any other models we want to attach that model, and we can make more than one such abstract models:

class Book(PublishInfoAttachedModel, 
           models.Model):
    pass

class NewsPaper(PublishInfoAttachedModel, 
           CommentsAttachedModel,  # if we have other attached model info
           models.Model):
    pass

Notice the models.Model class in the trailing super class list can be ignored, I wrote this is just to make the classes more obvious as a Model.

Leave a comment