pythondjango-rest-frameworkdjango-permissions

Object permissions for multiply objects in DRF


I can't prescribe permissions. I have Accounts, Sites and Informations models:

Accounts

class Accounts(models.Model):
    user = models.ForeignKey(to=User, on_delete=models.SET_NULL, null=True, editable=True, blank=True, verbose_name='Пользователь')
    name = models.CharField(max_length=255, unique=True, verbose_name='Название')

    def __str__(self):
        return self.name

Sites and Informations

class Sites(models.Model):
    account = models.ForeignKey(to=Accounts, on_delete=models.RESTRICT)
    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name


class Information(models.Model):
    site = models.ForeignKey(to=Sites, related_name='information', on_delete=models.RESTRICT)
    name_of_data = models.CharField(max_length=255)
    data = models.CharField(max_length=255)

    def __str__(self):
        return self.name_of_data

My view should return a list of sites and information for each site, depending on which account is requested (like /accounts/3 should return all sites and information that belong to the 3rd account). Here are my serializers for more understanding:

from .models import Information, Sites
from app.serializers import AccountsSerializer


class InformationSerializer(serializers.ModelSerializer):
    class Meta:
        model = Information
        fields = ['name_of_data', 'data']


class SitesSerializer(serializers.ModelSerializer):
    information = InformationSerializer(many=True, read_only=True)
    account = AccountsSerializer(read_only=True)

    class Meta:
        model = Sites
        fields = ['account', 'name', 'information']

Here is my view for this:

class ProfileView(ListAPIView):
     def list(self, request, *args, **kwargs):
         self.check_object_permissions()
         account_id = self.kwargs.get('account_id')
         queryset = Sites.objects.filter(account_id=account_id)
         serializer = SitesSerializer(queryset, many=True)
         return Response(serializer.data, status=status.HTTP_200_OK)

I need to restrict user access using the following rule:

  1. The user who is the owner of the requested account can view information about the account.

But I always get errors and always different errors.

In the above code Permissions is not checked at all and does not work.


Solution

  • First of all i think Accounts instance should be on the top level, then Sites, then Information. So in my opinion you should rebuild your serializers.

    Secondly, i dont think you need to fetch query params manually in this case - Try to use RetrieveAPIView.

    Technically, you dont need permissions for multiple objects. You check the rights to view the Accounts instance, after which you show the Account data and all data related to it (Sites and Information).

    Serializers
    from rest_framework.serializers import ModelSerializer
    
    
    class InformationSerializer(ModelSerializer):
        class Meta:
            model = Information
            fields = ["name_of_data", "data"]
    
    
    class SitesSerializer(ModelSerializer):
        information = InformationSerializer(many=True, read_only=True)
    
        class Meta:
            model = Sites
            fields = ["id", "information"]
    
    
    class AccountsRetrieveSerializer(ModelSerializer):
        sites = SitesSerializer(many=True, read_only=True)
    
        class Meta:
            model = Accounts
            fields = ["id", "name", "sites"]
    
    
    Permission class
    from rest_framework.permissions import BasePermission
    
    
    class IsObjectOwner(BasePermission):
        def has_object_permission(self, request, view, obj):
            return obj.user == request.user
    
    View
    from rest_framework.generics import RetrieveAPIView
    from rest_framework.permissions import IsAuthenticated
    
    
    class ProfileView(RetrieveAPIView):
        permission_classes = [IsAuthenticated, IsObjectOwner]
        serializer_class = AccountsRetrieveSerializer
    

    Hope it helped you a little.