Как получить Request.User в сериализаторе Django-Rest-Framework?

124

Пробовал что-то подобное, не получается.

class PostSerializer(serializers.ModelSerializer):

    class Meta:
        model = Post

    def save(self):
        user = self.context['request.user']
        title = self.validated_data['title']
        article = self.validated_data['article']

Мне нужен способ доступа к request.user из моего класса Serializer.

PythonIsGreat
источник
DRF CurrentUserDefaultабсолютно ❤️ django-rest-framework.org/api-guide/validators/…
andilabs

Ответы:

231

Вы не можете получить доступ к request.user прямой файлу. Вам нужно получить доступ к объекту запроса, а затем получить атрибут пользователя.

Как это:

user =  self.context['request'].user

Или чтобы быть в безопасности,

user = None
request = self.context.get("request")
if request and hasattr(request, "user"):
    user = request.user

Подробнее о дополнительном контексте можно прочитать здесь

karthikr
источник
1
там написаноNameError: name 'self' is not defined
Coderaemon
конечно, это было в контексте класса. Скорее всего, вы не в контексте класса
karthikr 06
3
В моем сериализаторе in validate()method self.context - это пустой dict. Зачем?
Дэвид Д.
14
Дэвид - вы, вероятно, уже давно решили эту проблему, но если у кого-то еще есть эта проблема, это может быть связано с тем, что вы создаете свой сериализатор вручную. У меня была эта проблема во вложенном сериализаторе, созданном для общих отношений. В документах говорится, что нужно сделать serializer = NoteSerializer (value), но это передаст только ваш экземпляр, а не контекст, содержащий запрос. Вы можете передать kwargs в конструктор и отправить ему необходимую информацию (см. Get_serializer или GenericAPIView, чтобы узнать, как он это делает)
Джон Воан,
2
@JonVaughan любая деталь, как передать kwargs экземпляру сериализатора ??
tyan
74

На самом деле, вам не нужно беспокоиться о контексте. Есть гораздо лучший способ сделать это:

from rest_framework.fields import CurrentUserDefault

class PostSerializer(serializers.ModelSerializer):

    class Meta:
        model = Post

   def save(self):
        user = CurrentUserDefault()  # <= magic!
        title = self.validated_data['title']
        article = self.validated_data['article']
Игорь Помаранский
источник
1
Это не сработало, оно вернуло объект Null. user_edit = serializers.CurrentUserDefault ()
Эндерсон Менезес
39

Как сказал Игорь в другом ответе, можно использовать CurrentUserDefault. Если вы не хотите переопределять метод сохранения только для этого, используйте doc :

from rest_framework import serializers

class PostSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
    class Meta:
        model = Post
IJR
источник
ссылка на документ теперь неверно связана.
coler-j
Ссылка на официальную документацию DRF с тем же примером django-rest-framework.org/api-guide/serializers/…
Паоло
2

Вы можете передать request.userпри вызове .save(...)внутри представления:

class EventSerializer(serializers.ModelSerializer):

    class Meta:
        model = models.Event
        exclude = ['user']


class EventView(APIView):

    def post(self, request):
        es = EventSerializer(data=request.data)
        if es.is_valid():
            es.save(user=self.request.user)
            return Response(status=status.HTTP_201_CREATED)
        return Response(data=es.errors, status=status.HTTP_400_BAD_REQUEST)

Это модель:

class Event(models.Model):
    user = models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    date = models.DateTimeField(default=timezone.now)
    place = models.CharField(max_length=255)
Макс Малыш
источник
0

Вам нужно небольшое изменение в сериализаторе:

class PostSerializer(serializers.ModelSerializer):

    class Meta:
        model = Post

    def save(self):
        user = self.context['request'].user
        title = self.validated_data['title']
        article = self.validated_data['article']

Вот пример использования наборов представлений для смешивания моделей. В createметоде вы можете найти правильный способ вызова сериализатора. get_serializer правильно заполняет контекстный словарь. Если вам нужно использовать другой сериализатор, определенный в наборе представлений, см. updateМетод о том, как запустить сериализатор с контекстным словарем, который также передает объект запроса сериализатору.

class SignupViewSet(mixins.UpdateModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):

    http_method_names = ["put", "post"]
    serializer_class = PostSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        kwargs['context'] = self.get_serializer_context()
        serializer = PostSerializer(instance, data=request.data, partial=partial, **kwargs)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)    
        return Response(serializer.data)
ВКТ
источник