2015-09-10 5 views
1

Я хочу создать API с разрешениями на уровне поля. Я получаю эти разрешения из таблицы базы данных, но где в структуре REST есть место, чтобы проверить, может ли пользователь выполнять операции CRUD в поле объекта?Django Rest Framework и разрешения на уровне поля

database --- model ---- ModelSerializer ---- ModelViewSet --- browser 

В ModelSerializer? Здесь я могу сбросить поля до того, как они попадут в представление, но у меня нет доступа к request.user по умолчанию, поэтому я должен реализовать это, что можно сделать, но не работает с другими 3-х партийными библиотеками. (django-rest-swagger)

или в ModelViewset? Где я могу переопределить список, создавать, обновлять и уничтожать методы, чтобы отбрасывать поля, к которым у пользователя нет доступа. Но это не очень хорошо работает с моей реализацией метаданных, потому что это получает метаданные непосредственно из сериализатора.

Или, может быть, оба? Например: капельный не разрешенные читает в сериализатор, когда модель извлекается по сериализатору и капельный не разрешенным-пишет в до того режима просмотра они получают передаются обратно в сериализаторе?

ответ

1

Существует хороший раздел в документах DRF о разрешениях here. Хорошее место для обработки (и проверки) находится в режиме просмотра. Для того, чтобы скопировать пример из документации:

from rest_framework.permissions import IsAuthenticated 
from rest_framework.response import Response 
from rest_framework.views import APIView 

class ExampleView(APIView): 
    permission_classes = (IsAuthenticated,) 

    def get(self, request, format=None): 
     content = { 
      'status': 'request was permitted' 
     } 
     return Response(content) 

Если вы хотите иметь пользовательские разрешения проверки вы можете определить свои собственные, а также указать заменить IsAuthenticated с собственным классом

1

Вы можете создавать различные сериализаторы в зависимости от поля для конкретного запроса. Затем вам нужно переопределить функцию get_serializer_class() в вашем представлении и решить сериализатор в соответствии с вашей логикой.

В соответствии с Документами DRF на get_serializer_class()

Может быть переопределен, чтобы обеспечить динамическое поведение, например, с использованием различных сериализаторов для операций чтения и записи, или предоставление различных сериализаторов к различным типам пользователей.

Например:

class MyView(..): 

    def get_serializer_class(self): 
     if self.request.user.is_staff: # check if staff user 
      return FullAccountSerializer 
     return BasicAccountSerializer 
    ... 
0

Если вы хотите реализовать пользовательское разрешение хорошо использовать modelviewset в ФПИ.

from rest_framework import status, viewsets 

class MyModelViewsets(viewsets.ModelViewSet): 
    queryset = # queryset 
    serializer_class = # serializer class 
    permission_classes = (# custom permission class her) 

Если вы хотите, чтобы все применить пользовательское разрешение на все конечные точки указать его в settings.py

REST_FRAMEWORK = { 

    'DEFAULT_PERMISSION_CLASSES': [ 
     'rest_framework.permissions.IsAuthenticated', 
     # add custom permission here 
    ] 
} 
0

Если вы используете GenericView, по умолчанию DRF поместить объект запроса в контекст объект сериализатора.Вы можете получить доступ к информации пользователя,

self.context['request'].user

0
from utils.mixins import MultiSerializerViewSetMixin 


class UserViewSet(MultiSerializerViewSetMixin, ModelViewSet): 
    serializer_class = UserSerializer 
    serializer_action_classes = { 
     'update': UserDetailSerializer, 
    } 
    permission_classes = (UserPermission,) 
    queryset = User.objects.all() 

исходный код для MultiSerializerViewSetMixin: https://gist.github.com/gonz/10044002

мне удалось мою проблему с двумя seriazliers:

from django.contrib.auth.models import User 
from rest_framework import serializers 


class UserSerializerMixin(serializers.Serializer): 
    id = serializers.IntegerField(read_only=True) 
    is_superuser = serializers.BooleanField(read_only=True) 
    first_name = serializers.CharField(max_length=30, required=False, allow_blank=True) 
    last_name = serializers.CharField(max_length=30, required=False, allow_blank=True) 
    email = serializers.EmailField(required=False, allow_blank=True) 

    def create(self, validated_data): 
     return User.objects.create_user(**validated_data) 

    def update(self, instance, validated_data): 
     instance.first_name = validated_data.get('first_name', instance.first_name) 
     instance.last_name = validated_data.get('last_name', instance.last_name) 
     instance.email = validated_data.get('email', instance.email) 
     password = validated_data.get('password', '') 
     if password: 
      instance.set_password(password) 
      instance.save() 
     return instance 

    class Meta: 
     model = User 


class UserSerializer(UserSerializerMixin): 
    username = serializers.CharField(max_length=30) 
    password = serializers.CharField(
     max_length=128, write_only=True, 
     style={'input_type': 'password'}) 


class UserDetailSerializer(UserSerializerMixin): 
    username = serializers.CharField(read_only=True) 
    password = serializers.CharField(
     max_length=128, write_only=True, 
     style={'input_type': 'password'}, 
     required=False, allow_blank=True 
    ) 

возможно вы мог бы использовать MultiSerializerViewSetMixin, я нашел его на работе в прошлом году и использовал mixins t o создать два разных, но похожих сериализатора.

Смежные вопросы