使用 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)。 尝试检查哪个函数获取数据,然后仅从中确定所需的字段。