将 类 与 django-filters 相关联

Associate classes with django-filters

您好,我有一个关于 django-filters 的问题。我的问题是: 我的 models.py 中定义了两个 classes,它们是:

class Volcano(models.Model):
    vd_id = models.AutoField("ID, Volcano Identifier (Index)",
                         primary_key=True)
    [...]

class VolcanoInformation(models.Model):

    # Primary key
    vd_inf_id = models.AutoField("ID, volcano information identifier (index)",
                             primary_key=True)

    # Other attributes
    vd_inf_numcal = models.IntegerField("Number of calderas")
    [...]

    # Foreign key(s)
    vd_id = models.ForeignKey(Volcano, null=True, related_name='vd_inf_vd_id',
                          on_delete=models.CASCADE)

他们两个是 link 通过 vd_id 属性编辑的。

我想开发一个搜索工具,允许用户按火山口数量 (vd_inf_numcal) 搜索火山。

我正在使用 django-filters,现在这是我的 filters.py:

from .models import *
import django_filters

class VolcanoFilter(django_filters.FilterSet):

    vd_name = django_filters.ModelChoiceFilter(
                                      queryset=Volcano.objects.values_list('vd_name', flat=True),
                                 widget=forms.Select, label='Volcano name',
                                 to_field_name='vd_name',
                                 )

    vd_inf_numcal = django_filters.ModelChoiceFilter(
                                   queryset=VolcanoInformation.objects.values_list('vd_inf_numcal', flat=True),
                                 widget=forms.Select, label='Number of calderas',
                                 )


    class Meta:
        model = Volcano
        fields = ['vd_name', 'vd_inf_numcal']

我的views.py是:

def search(request):
    feature_list = Volcano.objects.all()
    feature_filter = VolcanoFilter(request.GET, queryset = feature_list)

    return render(request, 'app/search_list.html', {'filter' : feature_filter, 'feature_type': feature_type})

在我的应用程序中,出现了可能的火山口数量的下拉列表,但搜索 returns 没有结果,这是正常的,因为 VolcanoInformation.vd_inf_numcal、VolcanoInformation.vd_id 和Volcano.vd_id.

它甚至说 "Select a valid choice. That choice is not one of the available choices."

我的问题是如何使用 django_filters 制作此 link? 我想我应该在 class 中写一些方法,但我完全不知道该怎么做。

如果有人知道答案,我将不胜感激!

一般来说,您需要回答两个问题:

  • 我们要查询什么字段以及需要生成什么 query/lookup 表达式。
  • 我们应该过滤什么样的值。

这些答案基本上是您 .filter() 电话的左侧和右侧。

在这种情况下,您要过滤火山-火山信息关系 (vd_inf_vd_id) 的反面,针对火山的破火山口数量 (vd_inf_numcal)。此外,您需要 exact 匹配。

对于值,您需要一组包含整数的选项。

AllValuesFilter 将查看数据库列并根据列值生成选择。然而,缺点是选择不会包含任何缺失值,这在呈现时看起来很奇怪。您可以调整此字段,或使用普通 ChoiceFilter,自行生成值。

def num_calderas_choices():
    # Get the maximum number of calderas
    max_count = VolcanoInformation.objects.aggregate(result=Max('vd_inf_numcal'))['result']

    # Generate a list of two-tuples for the select dropdown, from 0 to max_count
    # e.g, [(0, 0), (1, 1), (2, 2), ...]
    return zip(range(max_count), range(max_count))

class VolcanoFilter(django_filters.FilterSet):
    name = ...
    num_calderas = django_filters.ChoiceFilter(
        # related field traversal (note the connecting '__')
        field_name='vd_inf_vd_id__vd_inf_numcal',
        label='Number of calderas',
        choices=num_calderas_choices
    )

class Meta:
    model = Volcano
    fields = ['name', 'num_calderas']

请注意,我还没有亲自测试上面的代码,但它应该足够接近让你开始。

非常感谢!这正是我要找的!我不明白 .filter() 是如何工作的。

我对其他属性所做的是生成选择,但方式不同。例如,如果我只想显示可用位置的列表,我会使用:

# Location attribute
loc = VolcanoInformation.objects.values_list('vd_inf_loc', flat=True)
vd_inf_loc = django_filters.ChoiceFilter(
                              field_name='vd_inf_vd_id__vd_inf_loc',
                              label='Geographic location',
                              choices=zip(loc, loc),
                                        )