如何结合Django Filter与DAL实现字段链式筛选?
问题
尝试将Django Filters(DF)与Django Autocomplete Light(DAL)结合,实现多字段链式筛选:
- 选择特定国家;
- 筛选出所选国家下的所有地区;
- 筛选出所选地区下的所有城市。
已分别实现DF和DAL功能正常,单独测试DAL转发有效,但结合后仅国家字段自动完成正常,地区和城市字段无法正确筛选,控制台显示转发字典值未设置。
相关代码如下:
视图代码
class CountryAutoComplete(autocomplete.Select2QuerySetView): def get_queryset(self): qs = Country.objects.all() if self.q: qs = qs.filter(name__istartswith=self.q) return qs class RegionAutoComplete(autocomplete.Select2QuerySetView): def get_queryset(self): qs = Region.objects.all() country = self.forwarded.get("country", None) if country: qs = qs.filter(country=country) if self.q: qs = qs.filter(name__istartwith=self.q) return qs class CityAutoComplete(autocomplete.Select2QuerySetView): def get_queryset(self): qs = City.objects.all() # Base queryset for cities region = self.forwarded.get("region", None) # Get 'region' value from forwarded data if region: qs = qs.filter(region=region) # Correctly filter cities by region if self.q: # Filter cities based on the search query (q) qs = qs.filter(name__istartswith=self.q) return qs
Django Filter类代码
class RoomFilter(FilterSet): country = ModelChoiceFilter(lookup_expr="iexact", queryset=Country.objects.all(), widget=autocomplete.ModelSelect2(url="auth_app:country-autocomplete"), label=_("Land")) region = ModelChoiceFilter(lookup_expr="iexact", queryset=Region.objects.all(), widget=autocomplete.ModelSelect2(url="auth_app:region-autocomplete", forward=["country"]), label=_("Län")) city = ModelChoiceFilter(lookup_expr="iexact", queryset=City.objects.all(), widget=autocomplete.ModelSelect2(url="auth_app:city-autocomplete", forward=["region"]), label=_("Stad")) class Meta(): model = Room fields = ["country", "region", "city"]
Room模型代码
class Room(models.Model): member = models.ForeignKey(Member, on_delete=models.CASCADE, null=True, related_name="rooms") room_category = models.CharField(_("Kategori"), blank=False, choices=RoomCategory.choices(), max_length=100, default=RoomCategory.choices()[0][0]) title = models.CharField(_("Rubrik"), max_length=settings.ROOM_TITLE_LENGTH, blank=False, validators=[text_validator]) country = models.ForeignKey(Country, blank=False, max_length=128, on_delete=models.PROTECT) region = models.ForeignKey(Region, blank=False, max_length=128, on_delete=models.PROTECT) city = models.ForeignKey(City, blank=False, max_length=128, on_delete=models.PROTECT) description = models.TextField(_("Beskrivning"), blank=False, max_length=settings.ROOM_DESCRIPTION_LENGTH)
注:country、region、city字段为django cities light模型的外键。
解决方案
1. 修复视图中的拼写错误
RegionAutoComplete视图里的name__istartwith是拼写错误,应为name__istartswith,该错误会导致地区搜索筛选失效,甚至中断逻辑:
# 修正后的RegionAutoComplete代码 class RegionAutoComplete(autocomplete.Select2QuerySetView): def get_queryset(self): qs = Region.objects.all() country = self.forwarded.get("country", None) if country: qs = qs.filter(country=country) if self.q: qs = qs.filter(name__istartswith=self.q) # 修正拼写 return qs
2. 处理转发字段的类型转换
DAL转发的外键值是字符串类型的ID,直接用于外键筛选可能不匹配,需转换为整数:
# 修正RegionAutoComplete class RegionAutoComplete(autocomplete.Select2QuerySetView): def get_queryset(self): qs = Region.objects.all() country_id = self.forwarded.get("country") if country_id: try: qs = qs.filter(country_id=int(country_id)) except ValueError: pass # 忽略无效ID if self.q: qs = qs.filter(name__istartswith=self.q) return qs # 修正CityAutoComplete class CityAutoComplete(autocomplete.Select2QuerySetView): def get_queryset(self): qs = City.objects.all() region_id = self.forwarded.get("region") if region_id: try: qs = qs.filter(region_id=int(region_id)) except ValueError: pass if self.q: qs = qs.filter(name__istartswith=self.q) return qs
3. 优化Filter类的查询集
Filter中的ModelChoiceFilter无需手动指定queryset,DAL会自动通过Autocomplete视图获取动态筛选后的结果,手动指定静态查询集会覆盖动态逻辑:
class RoomFilter(FilterSet): country = ModelChoiceFilter( lookup_expr="iexact", widget=autocomplete.ModelSelect2(url="auth_app:country-autocomplete"), label=_("Land") ) region = ModelChoiceFilter( lookup_expr="iexact", widget=autocomplete.ModelSelect2(url="auth_app:region-autocomplete", forward=["country"]), label=_("Län") ) city = ModelChoiceFilter( lookup_expr="iexact", widget=autocomplete.ModelSelect2(url="auth_app:city-autocomplete", forward=["region"]), label=_("Stad") ) class Meta(): model = Room fields = ["country", "region", "city"]
4. 确保模板加载DAL资源
在渲染Filter表单的模板中,必须添加{{ filter.form.media }}标签,自动引入DAL的Select2 JS和CSS资源,保证转发联动的JS逻辑正常运行。
内容的提问来源于stack exchange,提问作者AJJ
相关产品推荐
相关产品推荐

