1

Scenario: there is different service types, i.e. clothes_washing, room_cleaning and room_maintenance. Each one of these services have common fields like service_date for example.

Upon scenario I have model for each service and a Service model with common fields. the relation between Service model and each service model is OneToOneField.

I've tried to override the delete() function in Service model following this answer and It works for me but for only one service (like wheel in self.wheel.delete()). but if I want to delete upon the service type? how to achieve that approach?

my models.py:

class ClothesWashing(models.Model):
    # special fields for clothes_washing
    service = models.OneToOneField(Service, on_delete=models.DO_NOTHING, null=True)

class RoomCleaning(models.Model):
    # special fields for room_cleaning 
    service = models.OneToOneField(Service, on_delete=models.DO_NOTHING, null=True)

class Service(models.Model):
    # common fields for all services

    def delete(self, *args, **kwargs):
        #here I wanna "roomcleaning" attribute to be dynamic upon content type
        self.roomcleaning.delete()
        return super(self.__class__, self).delete(*args, **kwargs)

Poula Adel
  • 609
  • 1
  • 10
  • 33

1 Answers1

1

You can set the on_delete parameters to CASCADE:

class ClothesWashing(models.Model):
    # special fields for clothes_washing
    service = models.OneToOneField(Service, on_delete=models.CASCADE, null=True)

class RoomCleaning(models.Model):
    # special fields for room_cleaning 
    service = models.OneToOneField(Service, on_delete=models.CASCADE, null=True)

The on_delete=… parameter [Django-doc] specifies what should happen when the item to which it refers is removed. So if Service is removed, and there is a ClothesWashing model that refers to it, then you can specify what to do.

By using CASCADE [Django-doc], you will remove the related ClothesWashing object as well, or as specified in the documentation:

Cascade deletes. Django emulates the behavior of the SQL constraint ON DELETE CASCADE and also deletes the object containing the ForeignKey.

It is better to implement it with this triggers, since methods like .delete() are not always called by the ORM when deleting in bulk. So Service.objects.all().delete() will delete all services, but will never call the .delete() method of your Service. By defining the triggers, you specify to Django what should happen with items that relate to it.

In this specific case, you perhaps might want to work with model inheritance [Django-doc]. Django can implement some boilerplate logic itself (like OneToOneFields to the parent model, etc.).

EDIT: If you want to delete the service if the given ClothesWashing, RoomCleaning, etc. are removed, you can override the .delete() method to delete that one too, you can for example make an abstract base class with:

class ServiceBase(models.Model):
    # special fields for clothes_washing
    service = models.OneToOneField(Service, on_delete=models.CASCADE, null=True)

    def delete(self, *args, **kwargs):
        service = self.service
        super().delete(*args, **kwargs)
        self.service.delete()

    class Meta:
        abstract = True

class ClothesWashing(ServiceBase):
    # …
    pass

class RoomCleaning(ServiceBase):
    # …
    pass

But likely if you use the ORM eventually some objects will not be removed, because of said ways to circumvent this.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • correct me if I got you wrong, that means if i set ```on_delete=models.CASCADE``` when I delete ```Service``` the ```ClothesWashing``` will be also deleted. but what if I deleted ```ClothesWashing```? will ```Service``` be deleted too ? – Poula Adel Apr 22 '20 at 17:31
  • 1
    @PoulaAdel: no, but that was not the case in your original design either. This is however not easy, since if you override `.delete()` it will *not* be triggered if you delete objects in bulk. But you can, as a "poor man solution" indeed override `.delete()` and hope that it does not happen. – Willem Van Onsem Apr 22 '20 at 17:33