Как отфильтровать модель поля "многие ко многим"?

Я пытаюсь реализовать геозону для парка грузовиков. Я должен связать список границ с транспортным средством. Кроме того, одно из требований-сохранить все, даже если оно удалено для целей аудита. Поэтому мы должны реализовать soft delete на всем. Вот в чем проблема. Поле "многие ко многим" не соответствует менеджеру мягкого удаления, оно включает как активные, так и неактивные записи в наборе данных поиска.

class Vehicle(SoftDeleteModel):
    routes = models.ManyToManyField('RouteBoundary', through='VehicleBoundaryMap', verbose_name=_('routes'),
                                    limit_choices_to={'active': True})


class VehicleBoundaryMap(SoftDeleteModel):
    vehicle = models.ForeignKey(Vehicle, verbose_name="vehicle")
    route_boundary = models.ForeignKey(RouteBoundary, verbose_name="route boundary")
    # ... more stuff here

    alive = SoftDeleteManager()


class SoftDeleteManager(models.Manager):

    use_for_related_fields = True

    def get_queryset(self):
        return SoftDeleteQuerySet(self.model).filter(active=True)

Как вы см. выше я попытался убедиться, что менеджер по умолчанию-это менеджер мягкого удаления (т. е. фильтр только для активных записей), а также попробуйте использовать limit limit_choices_to, но это, оказывается, поле внешней модели только не "через" модель, которую я хотел. Если у вас есть какие-либо предложения или рекомендации, я хотел бы услышать от вас.

спасибо!

2 ответов


первая проблема: использование limit_choices_to не будет работать, так как информация:

limit_choices_to не имеет никакого эффекта при использовании ManyToManyField С пользовательской промежуточной таблицей, указанной с помощью на VehicleBoundaryMap, а не objects поэтому он игнорируется.

единственный способ, который я вижу, который может работать быть:

  1. создать прокси-модель на VehicleBoundaryMap. Назовем это VehicleBoundaryMapProxy. Установите его так, чтобы его менеджер по умолчанию -SoftDeleteManager() что-то типа:

    class VehicleBoundaryMapProxy(VehicleBoundaryMap):
        class Meta:
            proxy = True
    
        objects = SoftDeleteManager()
    
  2. есть through='VehicleBounddaryMapProxy' на ManyToManyField:

     class Vehicle(SoftDeleteModel):
        routes = models.ManyToManyField('RouteBoundary', 
                                         through='VehicleBoundaryMapProxy', 
                                         verbose_name=_('routes'))
    

что, если вы просто сделаете:

class Vehicle(SoftDeleteModel):
    #you can even remove that field
    #routes = models.ManyToManyField('RouteBoundary', through='VehicleBoundaryMap', verbose_name=_('routes'),
    #                                limit_choices_to={'active': True})

    @property
    def routes(self):
        return RouteBoundary.objects.filter(
            vehicleboundarymap__active=True,
            vehicleboundarymap__vehicle=self,
        )

а теперь вместо vehicle.routes.clear() использовать vehicle.vehicleboundarymap_set.delete(). Вы потеряете только обратное отношение (RouteBoundary.vehicles), но вы можете реализовать его обратно, используя тот же способ.

остальное M2M field функции отключен в любом случае из-за промежуточной модели.