使用 Django-Filters 有条件地渲染字段
Render fields conditionally with Django-Filters
我正在开发我的 Django SAAS 应用程序,我希望允许用户在其中进行一些自定义设置,例如禁用或启用某些过滤器。为此,我使用 django-user-setttings combined with django-filters 和带有布尔字段的简单形式:
class PropertyFilterSetting(forms.Form):
filter_by_loans = forms.BooleanField(required=False)
filter_by_tenants = forms.BooleanField(required=False)
问题是,在尝试应用这些设置时,我将 运行 变成了严肃的意大利面条代码:
views.py
class PropertyListView(LoginRequiredMixin, FilterView):
template_name = 'app/property_list.html'
context_object_name = 'properties'
def get_filterset_class(self):
print(get_user_setting('filter_by_tenants', request=self.request))
return PropertyFilterWithoutTenant if not get_user_setting('filter_by_tenants', request=self.request)['value'] else PropertyFilter
filter.py
class PropertyFilter(django_filter.FilterSet):
...
class PropertyFilterWithoutTenant(PropertyFilter):
...
而且我必须对其余功能做同样的事情。有没有更好的方法来实现这个?
您可以在 User
模型中创建方法,或者创建一个新的 class 模型来存储所有方法。每个方法都会根据相应用户设置的值给你相关的过滤器集class。
类似于:
class UserFilterset:
def __init__(self, request):
self.request = request
def get_property_filterset(self):
if not get_user_setting('filter_by_tenants', request=self.request)['value']:
return PropertyFilterWithoutTenant
return PropertyFilter
... # add more such methods for each user setting
现在您可以使用此方法获取相关的过滤器集class
class PropertyListView(LoginRequiredMixin, FilterView):
template_name = 'app/property_list.html'
context_object_name = 'properties'
def get_filterset_class(self):
return UserFilterset(self.request).get_property_filterset()
所以即使以后你想添加更多的逻辑,你可以只更新相关的方法,这样会更干净和易于管理。
我不确定 MVT 结构将如何准确响应这个结构,但我在 REST 结构中使用自定义通用 class 在我想要的任何视图集中添加自定义过滤器字段
class ListAPIViewWithFilter(ListAPIView):
def get_kwargs_for_filtering(self):
filtering_kwargs = {}
if self.my_filter_fields is not []:
# iterate over the filter fields
for field in self.my_filter_fields:
# get the value of a field from request query parameter
field_value = self.request.query_params.get(field)
if field_value:
filtering_kwargs[field] = field_value
return filtering_kwargs
def get_queryset(self):
queryset = super(ListAPIViewWithFilter, self).get_queryset()
filtering_kwargs = self.get_kwargs_for_filtering()
if filtering_kwargs != {}:
# filter the queryset based on 'filtering_kwargs'
queryset = queryset.filter(**filtering_kwargs)
self.pagination_class = None
else:
return queryset
return queryset[:self.filter_results_number_limit]
在 views.py 中更改原始 get_queryset 函数应该是解决问题的关键(它适用于 django rest)。
尝试检查哪个函数获取数据,然后仅从中确定所需的字段。
我正在开发我的 Django SAAS 应用程序,我希望允许用户在其中进行一些自定义设置,例如禁用或启用某些过滤器。为此,我使用 django-user-setttings combined with django-filters 和带有布尔字段的简单形式:
class PropertyFilterSetting(forms.Form):
filter_by_loans = forms.BooleanField(required=False)
filter_by_tenants = forms.BooleanField(required=False)
问题是,在尝试应用这些设置时,我将 运行 变成了严肃的意大利面条代码:
views.py
class PropertyListView(LoginRequiredMixin, FilterView):
template_name = 'app/property_list.html'
context_object_name = 'properties'
def get_filterset_class(self):
print(get_user_setting('filter_by_tenants', request=self.request))
return PropertyFilterWithoutTenant if not get_user_setting('filter_by_tenants', request=self.request)['value'] else PropertyFilter
filter.py
class PropertyFilter(django_filter.FilterSet):
...
class PropertyFilterWithoutTenant(PropertyFilter):
...
而且我必须对其余功能做同样的事情。有没有更好的方法来实现这个?
您可以在 User
模型中创建方法,或者创建一个新的 class 模型来存储所有方法。每个方法都会根据相应用户设置的值给你相关的过滤器集class。
类似于:
class UserFilterset:
def __init__(self, request):
self.request = request
def get_property_filterset(self):
if not get_user_setting('filter_by_tenants', request=self.request)['value']:
return PropertyFilterWithoutTenant
return PropertyFilter
... # add more such methods for each user setting
现在您可以使用此方法获取相关的过滤器集class
class PropertyListView(LoginRequiredMixin, FilterView):
template_name = 'app/property_list.html'
context_object_name = 'properties'
def get_filterset_class(self):
return UserFilterset(self.request).get_property_filterset()
所以即使以后你想添加更多的逻辑,你可以只更新相关的方法,这样会更干净和易于管理。
我不确定 MVT 结构将如何准确响应这个结构,但我在 REST 结构中使用自定义通用 class 在我想要的任何视图集中添加自定义过滤器字段
class ListAPIViewWithFilter(ListAPIView):
def get_kwargs_for_filtering(self):
filtering_kwargs = {}
if self.my_filter_fields is not []:
# iterate over the filter fields
for field in self.my_filter_fields:
# get the value of a field from request query parameter
field_value = self.request.query_params.get(field)
if field_value:
filtering_kwargs[field] = field_value
return filtering_kwargs
def get_queryset(self):
queryset = super(ListAPIViewWithFilter, self).get_queryset()
filtering_kwargs = self.get_kwargs_for_filtering()
if filtering_kwargs != {}:
# filter the queryset based on 'filtering_kwargs'
queryset = queryset.filter(**filtering_kwargs)
self.pagination_class = None
else:
return queryset
return queryset[:self.filter_results_number_limit]
在 views.py 中更改原始 get_queryset 函数应该是解决问题的关键(它适用于 django rest)。 尝试检查哪个函数获取数据,然后仅从中确定所需的字段。