django-filter: extend filter query with request.user
Asked Answered
B

3

8

I'm need to add an additional filter property (in the background) to a django-filter request.

My Model:

class Event(models.Model):
  name=models.CharField(max_length=254)
  location=models.ForeignKey(Place)
  invited_user=models.ManyToManyField(User,null=True, blank=True)

With a filter those entries with the same location can be filtered. This is working.

Further on I have to exclude all those entries where the invited_user is not the request.user (choosing this filter property is only possible if the user has permissions).

Is this possible with django-filter, and if yes how?

My filter Class: import django_filters from models import Event

class EventFilter(django_filters.FilterSet):
    class Meta:
        model = Event
        fields = ['location']

My work is based on: How do I filter tables with Django generic views?

Berry answered 31/8, 2014 at 20:42 Comment(0)
S
7

you can access the request object in FilterSet.qs property.

class EventFilter(django_filters.FilterSet):
    class Meta:
        model = Event
        fields = ['location']
    
    @property
    def qs(self):
        queryset=super(EventFilter, self).qs
        if request.user.has_perm("app_label.has_permission"):       
            return queryset.exclude(invited_user!=self.request.user)
        return queryset      

docs https://rpkilby.github.io/django-filter/guide/usage.html#filtering-the-primary-qs

Sinful answered 12/7, 2018 at 15:25 Comment(0)
S
2

I think in your case you could do it by modifying the queryset in the view, where you should be able to access request.user. Therefore you wouldn't need to dig deep into django-filter,

In my case, when using dango_filters FilterView along with crispy forms to render the form, I wanted to hide fields from the form, along with additional filtering as you described, so I overrode get() for the FilterView, restricted the queryset to the user, and used crispy form's layout editing to pop the unwanted fields from the filter form:

def get(self, request, *args, **kwargs):
    """
    original code from django-filters.views.BaseFilterView - added admin check
    """
    filterset_class = self.get_filterset_class()
    self.filterset = self.get_filterset(filterset_class)
    self.object_list = self.filterset.qs
    # If not admin, restrict to assessor's own centre and clients
    if not request.user.get_profile().is_admin:
        self.object_list = self.object_list.filter(attendee__assessor=request.user)
        self.filterset.form.helper.layout[0].pop(2)  # centres filter
        self.filterset.form.helper.layout[0].pop(1)  # assessors filter
    context = self.get_context_data(filter=self.filterset,
                                    object_list=self.object_list)
    return self.render_to_response(context)
Schmo answered 13/9, 2014 at 11:12 Comment(0)
E
2

Try this:

class EventListView(BaseFilterView):
    ...
    def get_filterset(self, *args, **kwargs):
        fs = super().get_filterset(*args, **kwargs)
        fs.filters['location'].field.queryset = fs.filters['location'].field.queryset.filter(user=self.request.user)
        return fs
Endodermis answered 9/3, 2016 at 10:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.