django-filter:仅显示queryset

时间:2017-11-15 10:02:07

标签: django django-filter django-filters

我使用优秀的django-filter应用程序来过滤模型对象的查询集。但是,当我从视图中的查询集中包含.exclude()对象时,模板中的过滤器选择器仍会显示所有可用选项 - 甚至是我从查询集中排除的对象的选项。让我们说我的模型和视图如下:

#model
[...]
class Animal(models.Model):
    REGION_CHOICES = (
        (0, 'Africa'),
        (1, 'Europe'),
    )

    name = models.CharField(max_length=100)
    region = models.CharField(choices=REGION_CHOICES, max_length=100)
[...]

#view  
[...]  
qs = Animal.objects.all()
filter = AnimalFilter(request.GET, qs)
[...]

假设数据库中有两只动物:

zebra = Animal(name='Zebra', region='Africa')
frog = Animal(name='Frog', region'Europe')

当我在模板中渲染过滤器时,我正确地获得了包含欧洲和非洲两个选项的区域的选择器。 但是,如果我在视图中使用一些逻辑来查询集中的.exclude()对象:

#view
[...]
qs = Animal.objects.all().exclude(name='Frog')
filter = AnimalFilter(request.GET, qs)
[...]

现在,如果我在模板中渲染过滤器,我仍然可以获得区域的两个选项 Europe Africa ,尽管查询集只包含一个具有区域非洲。 任何想法如何为模板中呈现的区域字段获取正确的选项?非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

您可以覆盖choices中的FilterSet.__init__(),以确保区域选择仅限于基于提供的查询集的区域。

class AnimalFilter(FilterSet):
    def __init__(self, *args, **kwargs):
        super(AnimalFilter, self).__init__(*args, **kwargs)

        regions = self.queryset.values('region').distinct()
        region_choices = [(k, v) for k, v in REGION_CHOICES if k in regions]
        self.filters['region'].choices = region_choices

注意:我还没有对此进行测试,但希望足以让您指出正确的方向。

答案 1 :(得分:0)

夏尔巴人几乎拥有它:

class AnimalFilter(FilterSet):
    def __init__(self, *args, **kwargs):
        #we are going to need the form underneath the filter, so init parent
        super().__init__(*args, **kwargs)
        #use a flat values list to get a queryset list good enough for this
        #can wrap in list() to force evaluation and get list of values only
        regions = self.queryset.values_list('region',flat=True).distinct()
        region_choices = [(k, v) for k, v in REGION_CHOICES if k in regions]
        #filter hands off to subclassed form for widgets, attach there
        self.form.fields['region'].choices = region_choices