How to delete one-to-one relating models cascading in django?
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()
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
.