DRF Framework - разрешить пользователю CRUD на поле, связанное с другим пользователем, если они находятся в отношениях через другую модель

У меня есть модель Application, которая имеет поля applicant = ForeignKey('User'...) и coapplicant = ForeignKey('User'...).

Существует также модель Income, которая имеет поле user = ForeignKey('User'....

Я хочу разрешить пользователю A создавать, редактировать, удалять Income объекты пользователя B, если A и B находятся в отношениях через Application.

Это значит:

Пользователь A может CRUD доходы пользователя B и наоборот, если существует такой объект Application, где A является заявителем и B созаявителем или A является созаявителем и B заявителем.

Знаете ли вы, как это сделать?

Вы можете написать пользовательское разрешение примерно так:

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 

вы можете определить отношения "многие ко многим" между пользователем A и другими пользователями, такими как B (которых я буду называть coapplicants с этого момента), используя модель Application. и Django через поля

например:

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'...)
    

если вы хотите, чтобы оба A и B были в этом отношении, иначе просто используйте одно из applicant или coapplicant в through_fields. смотрите документацию здесь

теперь, когда вы определили отношения между ними, вы можете использовать разрешения на объекты отдыха в Django, чтобы дать пользователю B доступ к редактированию Income объектов, принадлежащих пользователю A. документация здесь

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()

если вы добавите это разрешение к ViewSet, работающей с Income объектами, obj аргументом, передаваемым has_object_permission функции, будет Income экземпляр.

Вернуться на верх