Bonjour,我有一个关于Django过滤器的问题。我的问题是: 我在models.py中定义了两个类:
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)
其中两个通过vd_id属性链接。
我想开发一种搜索工具,允许用户根据火山口的火山口数量(vd_inf_numcal)进行搜索。
我正在使用django-filters,现在这里是我的filter.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})
在我的应用程序中,出现了可能的破火山口数目的下拉列表,但搜索没有返回正常结果,因为VolcanoInformation.vd_inf_numcal,VolcanoInformation.vd_id和Volcano.vd_id之间没有关系。
甚至说“选择一个有效的选择。该选择不是可用的选择之一。”
我的问题是如何使用django_filters建立此链接? 我想我应该在该类中编写一些方法,但是我完全不知道该怎么做。
如果有人得到了答案,我将不胜感激!
答案 0 :(得分:0)
通常,您需要回答两个问题:
这些答案实质上是.filter()
通话的左手和右手。
在这种情况下,您将在Volcano-Volcano信息关系(vd_inf_vd_id
)的反面进行过滤,而不是针对火山的破火山口数量(vd_inf_numcal
)。此外,您需要exact
匹配项。
对于这些值,您需要一组包含整数的选项。
AllValuesFilter
将查看DB列并从列值中生成选择。但是,不利的一面是,这些选择将不包含任何缺少的值,这些值在呈现时看起来很奇怪。您可以改写该字段,也可以使用普通的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']
请注意,我还没有亲自测试以上代码,但是它应该足够接近以使您入门。
答案 1 :(得分:0)
非常感谢!那正是我想要的!我不了解.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),
)