pythondjangodjango-rest-frameworkpermissionsdjango-guardian

How to check django-guardian get_objects_for_user permissions via ForeignKey


I have two Django Models of the form:

from django.db import models


class Car(models.Model):
    pass

class Wheel(models.Model):
    car = models.ForeignKey(Car, related_name='wheels', on_delete=models.CASCADE)

I am using django-guardian to enforce object level permissions. The real application has a very large number of nested objects, and it was found that the write performance for creating all of the permission objects for every nested object was prohibitively slow. So instead, Users are granted permissions to the top level object (Car in this toy example).

On REST endpoints that access Wheel, the Django REST Framework permissions are checked by walking the foreign key upwards (in this case Wheel.car) to verify if a User should have access to a particular Wheel.

How could get_objects_for_user be used to get all of the Wheels for which a User has the appropriate permission for its parent Car?

Specifically trying to override django-rest-framework-guardian's ObjectPermissionsFilter.filter_queryset to support filtering objects based on the permissions of one of their ForeignKeys.


Solution

  • I was able to get this to work by defining this Filter for use with the Wheel ViewSet filter_backends:

    from rest_framework.filters import BaseFilterBackend
    
    
    class CarObjectPermissionsFilter(BaseFilterBackend):
        perm_format = '%(app_label)s.view_%(model_name)s'
    
        def filter_queryset(self, request, queryset, view):
            permission = cls.perm_format % {
                'app_label': Car._meta.app_label,
                'model_name': Car._meta.model_name,
            }
            car_ids = get_objects_for_user(user, permission, Car.objects.values_list('pk', flat=True))
            return queryset.filter(car__in=car_ids)