'DRF Framework - allow User CRUD on another Users related field if they are in relationship through another model
I have a model Application that has fields applicant = ForeignKey('User'...) and coapplicant = ForeignKey('User'...).
There is also a model Income that has field user = ForeignKey('User'....
I want to allow User A to create, edit, delete Income objects of User B if A and B are in a relationship through Application.
That means:
User A can CRUD Incomes of User B and vice-versa if there is such Application object where A is an applicant and B co-applicant or A is a co-applicant and B applicant.
Do you know how to make that work?
Solution 1:[1]
You can write custom permission something like this:
from django.db.models import F
class IsOwnerOrCoapplicant(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
if obj.user == request.user:
return True
# If application with both users exists return true,
# exclude cases when applicant and coapplicant are the same just in case
if Application.objects.filter(applicant__in=[obj.user, request.user], coapplicant__in=[obj.user, request.user]).exclude(applicant=F('coapplicant')).exists()
return True
return False
Solution 2:[2]
you can define a many-to-many relationship between User A and other Users like B (which I am going to call coapplicants from now) using the Application model. and Django through fields
for example:
from Django import models
class User(models.Model):
...
....
coapplicants = models.ManyToManyField(
'User',
through='Application',
through_fields=('applicant', 'coapplicant'),
)
class Application(models.Model):
applicant= models.ForeignKey('User',...)
coapplicant = models.ForeignKey('User'...)
if you want both A and B to be in this relationship, otherwise just use one of applicant or coapplicant in through_fields. check documentation here
now that you defined a relationship between them, you can use Django rest object permissions to give User B access to edit Income objects belonging to User A. documentation here
from rest_framework import permissions
class IsOwnerOrCoapplicant(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# assuming Income instance has an attribute named `owner`.
return obj.owner == request.user or request.user.coapplicants.filter(id=obj.owner.id).exists()
if you add this permission to a ViewSet that works with Income objects, obj argument passed to has_object_permission function is an Income instance.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | neverwalkaloner |
| Solution 2 | Nima Afshar |
