Search code examples
pythonpython-3.xdjangodjango-filter

Render fields conditionally with Django-Filters


I'm working on my Django SAAS app in which I want to allow the user to have some custom settings, like disable or enable certain filters. For that I'm using django-user-setttings combined with django-filters and simple forms with boolean fields:

class PropertyFilterSetting(forms.Form):
    filter_by_loans = forms.BooleanField(required=False)
    filter_by_tenants = forms.BooleanField(required=False)

The issue is that when trying to apply those settings, I keep running into serious spaghetti code:

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):
    ...

and I'd have to do the same thing with the rest of the features. Is there any better way to implement this?


Solution

  • You can create methods in your User model, or a new class which acts as a store for all the methods. Each method will give you the relevant filterset class based on the value of corresponding user setting.

    Something like:

    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
    
    

    Now you can use this method to get the relevant filterset 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()
    

    So even if in future you want to add some more logic, you can just update the relevant method, it would be cleaner and manageable.