如何通过多对多字段的模型进行过滤?

How to filter through Model of a many-to-many field?

我正在尝试为卡车车队实施地理围栏。我必须将边界列表与车辆相关联。最重要的是,其中一项要求是保留所有内容,即使出于审计目的而将其删除。因此我们必须对所有内容进行软删除。这就是问题所在。我的多对多字段不符合软删除管理器,它包括查找数据集中的活动记录和非活动记录。

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_choices_to 但结果是外来模型只是不是我想要的 "through" 型号。如果您有任何建议或建议,我很乐意听取您的意见。

谢谢!

第一个问题:您对 limit_choices_to 的使用不起作用,因为 documentation says:

limit_choices_to has no effect when used on a ManyToManyField with a custom intermediate table specified using the through parameter.

您正在使用 through,因此 limit_choices_to 无效。

第二个问题:你使用use_for_related_fields = True也是无效的。 documentation 表示这个属性:

If this attribute is set on the default manager for a model (only the default manager is considered in these situations), Django will use that class whenever it needs to automatically create a manager for the class.

您的自定义管理器分配给了 VehicleBoundaryMapalive 属性,而不是 objects,因此它被忽略了。

我认为可能有效的一种方法是:

  1. VehicleBoundaryMap 创建一个 proxy model。我们称它为 VehicleBoundaryMapProxy。设置它,使其默认管理器是 SoftDeleteManager() 类似于:

    class VehicleBoundaryMapProxy(VehicleBoundaryMap):
        class Meta:
            proxy = True
    
        objects = SoftDeleteManager()
    
  2. 你的ManyToManyFieldthrough='VehicleBounddaryMapProxy':

     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 特征无论如何都是 disabled 因为中间模型。