¿Cómo obtener Request.User en el serializador Django-Rest-Framework?

124

He intentado algo como esto, no funciona.

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']

Necesito una forma de poder acceder a request.user desde mi clase Serializer.

PythonIsGreat
fuente
DRF CurrentUserDefaultes absolutamente ❤️ django-rest-framework.org/api-guide/validators/…
andilabs

Respuestas:

231

No puede acceder request.userdirectamente. Debe acceder al objeto de solicitud y luego obtener el atributo de usuario.

Me gusta esto:

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

O para estar más seguro

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

Puede leer más sobre contexto adicional aquí

karthikr
fuente
1
diceNameError: name 'self' is not defined
Coderaemon
por supuesto, esto fue en el contexto de una clase. Lo más probable es que no estés en el contexto de una clase
karthikr
3
En mi serializador, en el validate()método, self.context es un diccionario vacío. ¿Por qué?
David D.
14
David: probablemente resolvió esto hace mucho tiempo, pero si alguien más tiene este problema, podría ser porque está construyendo su serializador manualmente. Tuve este problema en un serializador anidado instanciado para una relación genérica. Los documentos dicen que haga serializer = NoteSerializer (valor) pero esto solo pasará su instancia, no el contexto que contiene la solicitud. Puede pasar kwargs al constructor y enviarle la información que necesita (consulte get_serializer o GenericAPIView para saber cómo lo hace)
Jon Vaughan
2
@JonVaughan ¿algún detalle sobre cómo pasar kwargs a la instancia del serializador?
tyan
74

En realidad, no tienes que preocuparte por el contexto. Hay una forma mucho mejor de hacerlo:

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']
Igor Pomaranskiy
fuente
1
No funcionó, está devolviendo un objeto nulo. user_edit = serializers.CurrentUserDefault ()
Enderson Menezes
39

Como Igor mencionó en otra respuesta, el uso puede usar CurrentUserDefault. Si no desea anular el método de guardado solo para esto, use doc :

from rest_framework import serializers

class PostSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
    class Meta:
        model = Post
IJR
fuente
El vínculo del documento ahora está mal vinculado.
coler-j
Enlace a la documentación oficial de DRF con este mismo ejemplo django-rest-framework.org/api-guide/serializers/…
Paolo Melchiorre
2

Puede pasar request.useral llamar .save(...)dentro de una vista:

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)

Este es el modelo:

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)
Max Malysh
fuente
0

Necesita una pequeña edición en su serializador:

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']

Aquí hay un ejemplo, usando conjuntos de vistas de mezcla de modelos. En el createmétodo, puede encontrar la forma correcta de llamar al serializador. El método get_serializer llena el diccionario de contexto correctamente. Si necesita usar un serializador diferente al definido en el conjunto de vistas, consulte el updatemétodo sobre cómo iniciar el serializador con el diccionario de contexto, que también pasa el objeto de solicitud al serializador.

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)
cgl
fuente