如何过滤多对多字段的模型?
Posted
技术标签:
【中文标题】如何过滤多对多字段的模型?【英文标题】:How to filter through Model of a many-to-many field? 【发布时间】:2016-10-11 14:37:40 【问题描述】:我正在尝试为卡车车队实施地理围栏。我必须将边界列表与车辆相关联。最重要的是,即使出于审计目的而删除所有内容,也要保留所有内容。因此,我们必须对所有内容实施软删除。这就是问题所在。我的多对多字段不符合软删除管理器,它包括查找数据集中的活动和非活动记录。
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 但结果证明只使用外部模型而不是“通过”我想要的模型。如果您有任何建议或建议,我很乐意听取您的意见。
谢谢!
【问题讨论】:
与其自己实现软删除,不如使用django-reversion之类的东西。 那个软删除已经到处实现了,我不能再改变它了。我希望我们可以使用回归,它可以让我们避免很多头痛。 【参考方案1】:第一个问题:你不能使用limit_choices_to
,因为documentation says:
limit_choices_to
用于带有使用through
参数指定的自定义中间表的ManyToManyField
时无效。
您正在使用through
,所以limit_choices_to
无效。
第二个问题:你使用use_for_related_fields = True
也是无效的。 documentation 提到了这个属性:
如果在模型的 default 管理器上设置此属性(在这些情况下仅考虑默认管理器),Django 将在需要自动为该类创建管理器时使用该类.
您的自定义管理器被分配给VehicleBoundaryMap
的alive
属性而不是objects
,因此它被忽略了。
我认为可行的一种方法是:
为VehicleBoundaryMap
创建一个proxy model。我们称之为VehicleBoundaryMapProxy
。设置它,使其默认管理器为SoftDeleteManager()
类似:
class VehicleBoundaryMapProxy(VehicleBoundaryMap):
class Meta:
proxy = True
objects = SoftDeleteManager()
在您的ManyToManyField
上有through='VehicleBounddaryMapProxy'
:
class Vehicle(SoftDeleteModel):
routes = models.ManyToManyField('RouteBoundary',
through='VehicleBoundaryMapProxy',
verbose_name=_('routes'))
【讨论】:
让我试一试,目前看来很有希望。 效果很好,感谢 Louis 的解决方案。【参考方案2】:如果你只是这样做呢:
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.vehicleboundarymap_set.delete()
代替vehicle.routes.clear()
。您只会失去反向关系(RouteBoundary.vehicles
),但您可以使用相同的方式实现它。
由于中间模型,其余的M2M field
功能无论如何都是disabled。
【讨论】:
我喜欢你的想法,它在盒子外面。但是,由于我不能对其使用预取,这对我来说是一个很大的禁忌。以上是关于如何过滤多对多字段的模型?的主要内容,如果未能解决你的问题,请参考以下文章
如何过滤和访问 Django QuerySet 中的多对多字段?