Search code examples
pythondjangodjango-rest-frameworkpermissionsmany-to-many

How to define a 'IsOwner' custom permission for a many-to-many field in Django rest framework?


I'm very new in Django especially in Django-rest-framework. So in this project exercise of mine. And I want to have an object level permission, a IsOwner custom permission where authors are the only one who can modify it.

My Model looks like this:

#imports

class Book(models.Model):

    title = models.CharField(max_length=100)
    description = models.CharField(max_length=400)
    publisher = models.CharField(max_length=400)
    release_date = models.DateField()
    authors = models.ManyToManyField('Author', related_name='authors', blank=True)

    def __str__(self):
        return self.title
    
    

class Author(models.Model):

    user= models.ForeignKey(
        User, on_delete=models.CASCADE, default=1)
    biography  = models.TextField()
    date_of_birth = models.DateField()
    #books = models.ManyToManyField('Book', related_name='authors', blank=True)

    def __str__(self):
        return self.user.username

And this is the serializers

#imports here

class BookSerializer(serializers.ModelSerializer):
    
    class Meta:
        ordering = ['-id']
        model = Book
        fields = ("id", "title", "description", "publisher", "release_date", "authors")
        extra_kwargs = {'authors': {'required': False}}

class AuthorSerializer(serializers.ModelSerializer):
    books = BookSerializer(many=True, read_only=True)
    class Meta:
        ordering = ['-id']
        model = Author
        fields = ("id", "user", "biography", "date_of_birth", "books")
        extra_kwargs = {'books': {'required': False}}

and views.py is like this:

#imports here

class IsAnAuthor(BasePermission):
    message = 'Editing book is restricted to the authors only.'

    def has_object_permission(self, request, view, obj):
        
        if request.method in SAFE_METHODS:
            return True
        # I need to filter who can only edit book in this part but
        # obj.authors when print is none
        return obj.authors == request.user

class BookViewSet(viewsets.ModelViewSet):
    """
    List all workkers, or create a new worker.
    """
    permission_classes=[IsAnAuthor]
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [filters.OrderingFilter]
    ordering_fields = ['release_date']

class AuthorViewSet(viewsets.ModelViewSet):
    """
    List all workers, or create a new worker.
    """
    #permission_classes=[IsAuthenticatedOrReadOnly]
    queryset = Author.objects.all()
    serializer_class = AuthorSerializer

What I'm trying to achieve is a many-to-many relationship with Authors and Books and implement custom owner permission to it.


Solution

  • I think this is how it should be :

    class IsAnAuthor(BasePermission):
        message = 'Editing book is restricted to the authors only.'
    
        def has_object_permission(self, request, view, obj):
            
            if request.method in SAFE_METHODS:
                return True
            # I need to filter who can only edit book in this part but
            # obj.authors when print is none
            if request.user in obj.authors :
                return True
    
            return False