I'm facing an issue in my Django project related to soft deletion in many-to-many relationships using a through model. I'd appreciate any help or advice on how to resolve this issue.
I have three models in my application: Author, Book, and BookAuthor. The many-to-many relationship between Author and Book is defined through the BookAuthor model. Here are the definitions of my models:
from django.db import models
class Author(SoftDeleteModel):
name = models.CharField(max_length=100)
class Book(SoftDeleteModel):
title = models.CharField(max_length=200)
authors = models.ManyToManyField(Author, through='BookAuthor', related_name='books')
class BookAuthor(SoftDeleteModel):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
class Meta:
# Other necessary meta definitions
pass
The issue arises when I soft delete a relationship in the BookAuthor model and then try to access the books of an author using the query author.books.all(). Even though I have soft deleted the relationship in BookAuthor, I still see all the books associated with the author.
I'm using the django-soft-delete package (https://pypi.org/project/django-soft-delete/),
Does anyone have any suggestions on how I can address this issue and ensure that softly deleted relationships are not displayed when accessing through the many-to-many relationship?
Any help or advice would be greatly appreciated! Thank you in advance!
After some further investigation, I managed to resolve the issue by modifying the SoftDeleteManager provided by the django-soft-delete package. Here's the modified SoftDeleteManager with additional logic to filter out softly deleted relationships when accessed through a many-to-many relationship:
from django.db import models
from soft_delete.managers import SoftDeleteQuerySet
class SoftDeleteManager(models.Manager):
def get_queryset(self):
return SoftDeleteQuerySet(self.model, self._db).filter(is_deleted=False)
def _apply_soft_delete_filter(self, queryset):
return queryset.filter(is_deleted=False)
def _apply_soft_delete_filter_if_needed(self, queryset):
if self.__class__.__name__ == 'ManyRelatedManager':
related_name = getattr(self.through, self.target_field_name).field._related_name
filter_kwargs = {f'{related_name}__is_deleted': False}
queryset = queryset.filter(is_deleted=False, **filter_kwargs)
return queryset.filter(is_deleted=False)
def all(self, *args, **kwargs):
queryset = self.get_queryset()
return self._apply_soft_delete_filter_if_needed(queryset)
def filter(self, *args, **kwargs):
queryset = self.get_queryset()
queryset = self._apply_soft_delete_filter_if_needed(queryset)
return queryset.filter(*args, **kwargs)
def get(self, *args, **kwargs):
queryset = self.get_queryset()
queryset = self._apply_soft_delete_filter_if_needed(queryset)
return queryset.get(*args, **kwargs)
This modification ensures that softly deleted relationships are not displayed when accessed through the many-to-many relationship. If you encounter any issues or have further questions, feel free to ask!