darkvodka
darkvodka

Reputation: 333

what is the best way to filter result in modelviewset per user?

I am creating an api with Django rest framework. I use only ModelViewsSet. I need the result of some viewset to be different depending on the user who makes the request.

For the moment I have overloaded the get_query_set method for each ModelViewSet. This works very well, depending on the user the results are different for the "list" and also for the "read" which returns a 404 if the user tries to access an element he doesn't have the right to.

    def get_queryset(self):
        if self.request.user.is_staff:
            return cache.get_or_set(
                'machine_machines_list',
                Machine.objects.all() \
                    .select_related('category') \
                    .prefetch_related('machine_stock') \
                    .prefetch_related('components'),
                60)
        else:
            return cache.get_or_set(
                    f'machine_machines_list_user_{self.request.user.pk}',
                    Machine.objects.filter(site__user=self.request.user)\
                                    .select_related('category') \
                                    .prefetch_related('machine_stock') \
                                    .prefetch_related('components'),
                    60)

However I'm not sure if this is the best method or if it is really secure. Is it the right method? Or is there a better way to do it?

Upvotes: 1

Views: 553

Answers (1)

Alexandr Tatarinov
Alexandr Tatarinov

Reputation: 4034

That's a good option. Actually, that's basically the only option to limit the list response, and also giving you "for free" checks for the read/update/delete. I would recommend to clean-up it a bit though to reduce duplication and improve clarity:

def get_queryset(self):
    queryset = Machine.objects\
                .select_related('category') \
                .prefetch_related('machine_stock', 'components')
    user = self.request.user
    if user.is_staff:
        cache_key = 'machine_machines_list'
    else:
        queryset = queryset.filter(site__user=user)
        cache_key = f'machine_machines_list_user_{user.pk}'
    
    return cache.get_or_set(cache_key, queryset, 60)

Upvotes: 2

Related Questions