How to gently remove many of many relationships with Django

In my Django project, all entities deleted by the user should be gently deleted by setting the current datetime property to deleted_at. My model looks like this: Trip ↔ TripDestination ↔ Destination (many-many). In other words, a trip can have multiple destinations.

When I delete Trip, SoftDeleteManager filters the entire deleted trip. However, if I request all trip destinations (using get_object_or_404 (Trip, pk = id)), I also get deleted ones (i.e. TripDestination Models with deleted_at == null OR deleted_at! = Null). I really do not understand why, since all my models are inherited from LifeTimeTracking and use SoftDeleteManager.

Can someone please help me understand why SoftDeleteManager does not work for n: m relationship?

class SoftDeleteManager(models.Manager):
    def get_query_set(self):
        query_set = super(SoftDeleteManager, self).get_query_set()
        return query_set.filter(deleted_at__isnull = True)

class LifeTimeTrackingModel(models.Model):
    created_at = models.DateTimeField(auto_now_add = True)
    updated_at = models.DateTimeField(auto_now = True)
    deleted_at = models.DateTimeField(null = True)

    objects = SoftDeleteManager()
    all_objects = models.Manager()

    class Meta:
        abstract = True

class Destination(LifeTimeTrackingModel):
    city_name = models.CharField(max_length = 45)

class Trip(LifeTimeTrackingModel):
    name = models.CharField(max_length = 250)
    destinations = models.ManyToManyField(Destination, through = 'TripDestination')

class TripDestination(LifeTimeTrackingModel):
    trip = models.ForeignKey(Trip)
    destination = models.ForeignKey(Destination)

Resolution I registered error 17746 in DBG DBG. Thanks to Caspar for helping with this.

+5
source share
2 answers

It seems that this behavior comes from ManyToManyField, which wants to use its own manager, which is referenced by related objects , because when I try to make some of my own instances and try to gently delete them using your model code (via the manage shell. py) everything works as intended.

, , . 15 ManyToManyField, , ( django/db/models/fields/related.py).

, , use_for_related_fields = True SoftDeleteManager, :

class SoftDeleteManager(models.Manager):
    use_for_related_fields = True

    def get_query_set(self):
        query_set = super(SoftDeleteManager, self).get_query_set()
        return query_set.filter(deleted_at__isnull = True)

: Trip 2 Destination s, TripDestination, Destination deleted_at datetime.datetime.now(), Destination , mytrip.destinations.all(), , , .

, , , get_query_set() , , , , .

+2

deleted_at Destinantion Trip use_for_related_fields = True SoftDeleteManager, . Caspar, Destinations trip_object.destinations.all().

, Destinations, Trip TripDestination deleted_at, aka soft delete .

, . - , .

trip_object.destinantions.some_method() Destination. destinantion_object.trip_set.some_method() Trip. TripDestination .

trip_object.destinantions.through.objects.some_method(), . Trip.get_destinations Destination.get_trips, .

, , :

class DestinationManager(models.Manager):
    use_for_related_fields = True

    def get_query_set(self):
        query_set = super(DestinationManager, self).get_query_set()
        if hasattr(self, "through"):
            through_objects = self.through.objects.filter(
                destination_id=query_set.filter(**self.core_filters).get().id,
                trip_id=self._fk_val,
                deleted_at__isnull=True)
            query_set = query_set.filter(
                id__in=through_objects.values("destination_id"))

        return query_set.filter(deleted_at__isnull = True)

TripManager, . django/db/models/fields/related.py .

get_queryset , . Trip.get_destinations .

+2

All Articles