Django多数据库场景下配置FilterSet指定数据库并更新过滤字段
解决Django多数据库下django-filter指定数据库的问题
问题场景
我开发的Django应用需对接多个结构一致的数据库,数据库名称作为URL参数传入视图(self.kwargs['db'])。当前使用django-tables2结合django-filter(基于SingleTableMixin, FilterView)展示表格数据,但FilterSet默认使用默认数据库,需配置其使用指定数据库来填充过滤字段。现有代码如下:
filters.py
class FooFilter(django_filters.FilterSet): class Meta: model = Foo fields = ['project', 'fooclass']
views.py
class FilteredFooView(SingleTableMixin, FilterView): template_name = "metadata/metadata-filtered-table.html" table_pagination = False table_class = FooTable model = Foo filterset_class = FooFilter def get_queryset(self): return Foo.objects.using(self.kwargs['db']).all() # sets db for the table def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) template_input = {'item': 'FooItem', 'name': getName(self.kwargs['db'])} context = {**template_input, **context, **self.kwargs} return context
解决方案
要让FilterSet使用指定数据库,需通过修改FilterSet的初始化逻辑,结合视图传递数据库参数来实现:
- 修改FilterSet类,支持传入数据库别名
在filters.py中重写__init__方法,接收using参数,并为所有带查询集的过滤字段设置指定数据库:
import django_filters from .models import Foo class FooFilter(django_filters.FilterSet): class Meta: model = Foo fields = ['project', 'fooclass'] def __init__(self, *args, using=None, **kwargs): super().__init__(*args, **kwargs) if using: # 遍历所有过滤字段,将查询集切换到指定数据库 for filter_obj in self.filters.values(): if hasattr(filter_obj, 'queryset'): filter_obj.queryset = filter_obj.queryset.using(using)
- 在视图中传递数据库参数给FilterSet
在views.py中重写get_filterset方法,把URL参数里的数据库名传入FilterSet的初始化参数:
from django.views.generic import FilterView from django_tables2.views import SingleTableMixin from .filters import FooFilter from .models import Foo from .tables import FooTable class FilteredFooView(SingleTableMixin, FilterView): template_name = "metadata/metadata-filtered-table.html" table_pagination = False table_class = FooTable model = Foo filterset_class = FooFilter def get_queryset(self): return Foo.objects.using(self.kwargs['db']).all() # 为表格数据指定数据库 def get_filterset(self, filterset_class): filter_kwargs = self.get_filterset_kwargs(filterset_class) # 传入数据库别名到FilterSet filter_kwargs['using'] = self.kwargs['db'] return filterset_class(**filter_kwargs) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) template_input = {'item': 'FooItem', 'name': getName(self.kwargs['db'])} context = {**template_input, **context, **self.kwargs} return context
修改完成后,FilterSet的过滤选项会从URL参数指定的数据库中获取,和表格数据的数据源保持一致。
内容的提问来源于stack exchange,提问作者Elena Klimenko
相关产品推荐
相关产品推荐

