Reputation: 6448
I am trying to enforce row (object) level permissions in Django, on the model level.
All the resources on the web revolve around two possible solutions:
Option 1. Passing the request manually to a custom manager with a for_user()
method:
# manager
class EntryManager(models.Manager):
def for_user(self, user):
return self.get_queryset().filter(owner=user)
# model
class Entry(models.Model):
owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
objects = EntryManager()
# usage in views/serializers/forms/admin/...
Entry.objects.for_user(request.user)
Option 2: Using threading.local()
variables to store the request/user in the middleware, and than access them in the model.
Examples: https://github.com/citusdata/django-multitenant
https://github.com/benrobster/django-threadlocals
https://github.com/Alir3z4/django-crequest
https://www.viget.com/articles/multi-tenancy-in-django/
I don't like option 1, because it relies on a developer calling a for_user()
method, which can be often forgotten.
There are a lot of people on the internet that don't like option 2, because of the usage of threadlocals and also because of a Django philosophy that models should be request-unaware.
I am coming from a framework such as Laravel which allows access to the Request and User at all levels, so I am puzzled why this is a no-no in Django.
I did take a look at django-guardian as well, but the module seems quite complex, and no easy way to filter out all objects linked to a user. Also from what I got, it could not be implemented on the model level.
QUESTION: My question is, is there any other good way to implement Row Level permissions on the Model level, without relying on developers to pass request objects to the Model Manager?
I have shifted my focus on making the Model Manager unusable unless for_request()
is called, but there are pitfalls in that direction as well.
Upvotes: 3
Views: 231