gpt4 book ai didi

python - 如何使用ModelMultipleChoiceFilter?

转载 作者:太空狗 更新时间:2023-10-29 17:59:26 28 4
gpt4 key购买 nike

我一直在尝试让 ModelMultipleChoiceFilter 工作几个小时,并且阅读了 DRF 和 Django 过滤器文档。

我希望能够根据通过 ManyToManyField 分配给网站的标签过滤一组网站。例如,我希望能够获得已标记为“ cooking ”或“养蜂”的网站列表。

这是我当前 models.py 的相关片段:

class SiteTag(models.Model):
"""Site Categories"""
name = models.CharField(max_length=63)

def __str__(self):
return self.name

class Website(models.Model):
"""A website"""
domain = models.CharField(max_length=255, unique=True)
description = models.CharField(max_length=2047)
rating = models.IntegerField(default=1, choices=RATING_CHOICES)
tags = models.ManyToManyField(SiteTag)
added = models.DateTimeField(default=timezone.now())
updated = models.DateTimeField(default=timezone.now())

def __str__(self):
return self.domain

还有我当前的 views.py 片段:

class WebsiteFilter(filters.FilterSet):
# With a simple CharFilter I can chain together a list of tags using &tag=foo&tag=bar - but only returns site for bar (sites for both foo and bar exist).
tag = django_filters.CharFilter(name='tags__name')

# THE PROBLEM:
tags = django_filters.ModelMultipleChoiceFilter(name='name', queryset=SiteTag.objects.all(), lookup_type="eq")

rating_min = django_filters.NumberFilter(name="rating", lookup_type="gte")
rating_max = django_filters.NumberFilter(name="rating", lookup_type="lte")

class Meta:
model = Website
fields = ('id', 'domain', 'rating', 'rating_min', 'rating_max', 'tag', 'tags')

class WebsiteViewSet(viewsets.ModelViewSet):
"""API endpoint for sites"""
queryset = Website.objects.all()
serializer_class = WebsiteSerializer
filter_class = WebsiteFilter
filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,)
search_fields = ('domain',)
ordering_fields = ('id', 'domain', 'rating',)

我刚刚使用查询字符串 [/path/to/sites]?tags=News 进行了测试,我 100% 确定适当的记录存在(如所述) ?tag(缺少 s)查询。

我尝试过的其他事情的一个例子是:

tags = django_filters.ModelMultipleChoiceFilter(name='tags__name', queryset=Website.objects.all(), lookup_type="in")

如果网站标签满足 name == A OR name == B OR name == C,我该如何返回任何网站?

最佳答案

我在尝试为自己解决一个几乎相同的问题时偶然发现了这个问题,虽然我本可以编写一个自定义过滤器,但你的问题让我很感兴趣,我不得不深入挖掘!

事实证明,ModelMultipleChoiceFilter 仅对普通 Filter 进行了一次更改,如以下 django_filters 源代码所示:

class ModelChoiceFilter(Filter):
field_class = forms.ModelChoiceField

class ModelMultipleChoiceFilter(MultipleChoiceFilter):
field_class = forms.ModelMultipleChoiceField

也就是说,它将 field_class 更改为 Django 内置表单中的 ModelMultipleChoiceField

查看 ModelMultipleChoiceField 的源代码,__init__() 的必需参数之一是 queryset,所以您在那里有正确的轨道。

另一 block 拼图来自 ModelMultipleChoiceField.clean() 方法,其中一行:key = self.to_field_name or 'pk'。这意味着默认情况下它将接受您传递给它的任何值(例如,“cooking”)并尝试查找 Tag.objects.filter(pk="cooking"),显然我们希望它查看名称,正如我们在那行中看到的,它比较的字段由 self.to_field_name 控制。

幸运的是,django_filtersFilter.field() 方法在实例化实际字段时包含以下内容。

self._field = self.field_class(required=self.required,
label=self.label, widget=self.widget, **self.extra)

特别值得注意的是 **self.extra,它来自 Filter.__init__():self.extra = kwargs,所以我们需要做的就是将一个额外的to_field_name kwarg 传递给ModelMultipleChoiceFilter,它将传递给底层的ModelMultipleChoiceField

所以(跳过此处查看实际解决方案!),您想要的实际代码是

tags = django_filters.ModelMultipleChoiceFilter(
name='sitetags__name',
to_field_name='name',
lookup_type='in',
queryset=SiteTag.objects.all()
)

所以您与上面发布的代码非常接近!我不知道此解决方案是否与您相关,但希望它能在将来帮助其他人!

关于python - 如何使用ModelMultipleChoiceFilter?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26210217/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com