johnthagen
johnthagen

Reputation: 9189

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.

Upvotes: 1

Views: 971

Answers (1)

johnthagen
johnthagen

Reputation: 9189

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)

Upvotes: 2

Related Questions