Customize queryset in django-filter ModelChoiceFilter (select) and ModelMultipleChoiceFilter (multi-select) menus based on request

瘦欲@ 提交于 2020-05-24 04:37:44

问题


I'm using django-filter in 2 places: My Django Rest Framework API, and in my FilterViews (Django Filter's Generic ListViews.) In the case of my FilterViews I'm showing both select boxes (ModelChoiceFilter) and multi-select boxes (ModelMultipleChoiceFilter) to be filtered on.

I need to be able to limit what's in those select and multi-select inputs based on a field inside the request.

It's relatively simple to change what's listed as a kwarg in the relevant field in the FilterSet. For example, here's my FilterSet where the queryset is set as a kwarg:

class FieldFilter(django_filters.FilterSet):
    """Filter for the field list in the API"""
    dataset = ModelChoiceFilter(queryset=Dataset.objects.all())

    class Meta(object):
        """Meta options for the filter"""
         model = Field
         fields = ['dataset']

And it's relatively straightforward to limit what the result is in DRF inside the get_queryset() method. For example, here's my DRF ViewSet:

class FieldViewSet(viewsets.ReadOnlyModelViewSet):
    """A ViewSet for viewing dataset fields"""
    queryset = Field.objects.all()
    serializer_class = FieldSerializer
    filter_class = FieldFilter

    def get_queryset(self):
        """Get the queryset"""
        queryset = super(FieldViewSet, self).get_queryset()

        queryset = queryset.filter(
            dataset__organization=self.request.organization)

        return queryset

I just can't find anywhere to edit the Dataset field in the filter_class when the view is being displayed.

This is super straightforward in Django FormView generic views, but it doesn't appear that FieldViewSet follows the same get_form() structure as generic views. It's also relatively straightforward to do in the admin, but DRF/Django-Filter don't seem to follow that structure either.

Is there any way to customize the queryset in those inputs on a per-request basis? Preferably both on FilterViews and in the HTML API browser, but just in FilterViews would be fine if it's too complicated for the HTML API browser.


回答1:


After hours of search, I found the solution in the official documentation here!

The queryset argument for ModelChoiceFilter and ModelMultipleChoiceFilter supports callable behavior. If a callable is passed, it will be invoked with the request as its only argument.

import django_filters as filters
from django.utils.translation import gettext as _

def ourBranches(request):
    if request is None:
        return Branch.objects.none()

    company = request.user.profile.company
    return Branch.objects.filter(company=company)


class UnitFilter(filters.FilterSet):
    branch = filters.ModelChoiceFilter(
        queryset=ourBranches, empty_label=_("All Branches"))

    class Meta:
        model = Unit
        fields = ('branch', )

and in the view, I made sure to pass the request as well

 qs = Unit.objects.all()
 filter = UnitFilter(self.request.GET, request=self.request, queryset=qs) 
 table = UnitTable(filter.qs)



回答2:


I also had problems finding a resolution to this.

I solved it (I think) via the following:

views.py

table_filter = ExampleFilter(request.GET, kwarg_I_want_to_pass=request.user, queryset=qs)

filters.py

class ExampleFilter(django_filters.FilterSet):

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('kwarg_I_want_to_pass', None)
        super(ExampleFilter, self).__init__(*args, **kwargs)

        self.filters['field_to_filter'].extra.update({
           'queryset': Supplier.objects.filter(related_user=self.user),
           'empty_label': '',
           'help_text': False
        })

    class Meta:
        model = ExampleModel
        fields = ['related_user', 'field_to_filter', ... other fields]


来源:https://stackoverflow.com/questions/50206820/customize-queryset-in-django-filter-modelchoicefilter-select-and-modelmultiple

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!