foo
foo

Reputation: 275

Django-REST foreign key object permissions

I have following django models:

class Photo(models.Model):
    album = models.ForeignKey('Album', related_name='photos')
    owner = models.ForeignKey('auth.User')

class Album(models.Model):
    title = models.CharField(max_length=100)
    owner = models.ForeignKey('auth.User')

And IsOwner permission

class IsOwner(permissions.BasePermission):
    """
    Custom permission to only allow owners to get it.
    """

    def has_object_permission(self, request, view, obj):

        return obj.owner == request.user

I need to prevent creation of Albums with photos owned by other users. At the moment I using this solution:

class AlbumSerializer(serializers.ModelSerializer):

    def create(self, validated_data):
        photos = validated_data.pop('photos')

        for _photo in photos:
            ph_obj = Photo.objects.get(id=_photo['id'])
            if self.context['request'].user == ph_obj.owner:
                ph_obj.album = album
                ph_obj.save()

But it doesn't feel quite right. Also I think that serializer must raise some kind of exception for this case. How to perform it? Thanks.

Upvotes: 3

Views: 1483

Answers (1)

ilse2005
ilse2005

Reputation: 11429

You can write a custom permission for the AlbumSerializer to do the check:

class CustomerAccessPermission(permissions.BasePermission):
    message = 'You can only add your photos!'

    def has_permission(self, request, view):

        if view.action == 'create':
            for photo in request.POST.get('photos'):
                if not Photo.objects.filter(id=photo['id'], owner=request.user).exists():
                    return False
        return True

or maybe better with only one db query:

class CustomerAccessPermission(permissions.BasePermission):
    message = 'You can only add your photos!'

    def has_permission(self, request, view):

        if view.action == 'create':
            user_photos = Photo.objects.filter(owner=request.user).values_list('id', flat=True)
            for photo in request.POST.get('photos'):
                if not photo['id'] in user_photos:
                    return False
        return True

Upvotes: 3

Related Questions