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)
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 theForeignKey
.
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 OneToOneField
s 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.