Comment obtenir Request.User dans le sérialiseur Django-Rest-Framework?

124

J'ai essayé quelque chose comme ça, ça ne marche pas.

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

J'ai besoin d'un moyen d'accéder à request.user depuis ma classe Serializer.

PythonIsGreat
la source
DRF CurrentUserDefaultest absolument ❤️ django-rest-framework.org/api-guide/validators/…
andilabs

Réponses:

231

Vous ne pouvez pas accéder request.userdirectement au. Vous devez accéder à l'objet de requête, puis récupérer l'attribut utilisateur.

Comme ça:

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

Ou pour être plus sûr,

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

Plus d'informations sur le contexte supplémentaire peuvent être lues ici

karthikr
la source
1
il ditNameError: name 'self' is not defined
Coderaemon
bien sûr, c'était dans le contexte d'une classe. Vous n'êtes probablement pas dans le contexte d'un cours
karthikr
3
Dans mon sérialiseur, dans validate()method, self.context est un dict vide. Pourquoi?
David D.
14
David - vous avez probablement résolu ce problème il y a longtemps, mais si quelqu'un d'autre a ce problème, c'est peut-être parce que vous construisez votre sérialiseur manuellement. J'ai eu ce problème dans un sérialiseur imbriqué instancié pour une relation générique. La documentation dit de faire serializer = NoteSerializer (valeur) mais cela ne transmettra que votre instance, pas le contexte contenant la requête. Vous pouvez passer kwargs au constructeur et lui envoyer les informations dont il a besoin (voir get_serializer ou GenericAPIView pour savoir comment il le fait)
Jon Vaughan
2
@JonVaughan tout détail comment passer des kwargs à l'instance du sérialiseur ??
tyan
74

En fait, vous n'avez pas à vous soucier du contexte. Il existe une bien meilleure façon de le faire:

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
la source
1
Cela n'a pas fonctionné, il renvoie un objet Null. user_edit = serializers.CurrentUserDefault ()
Enderson Menezes
39

Comme Igor l'a mentionné dans une autre réponse, l'utilisation peut utiliser CurrentUserDefault. Si vous ne souhaitez pas remplacer la méthode de sauvegarde uniquement pour cela, utilisez doc :

from rest_framework import serializers

class PostSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
    class Meta:
        model = Post
IJR
la source
Le lien doc est maintenant mal lié.
coler-j
Lien vers la documentation officielle DRF avec ce même exemple django-rest-framework.org/api-guide/serializers/…
Paolo Melchiorre
2

Vous pouvez passer request.userlors d'un appel .save(...)dans une vue:

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)

Voici le modèle:

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
la source
0

Vous avez besoin d'une petite modification dans votre sérialiseur:

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

Voici un exemple, utilisant des ensembles de vues de mélange de modèle. Dans createmethod, vous pouvez trouver la bonne façon d'appeler le sérialiseur. La méthode get_serializer remplit correctement le dictionnaire contextuel. Si vous devez utiliser un sérialiseur différent de celui défini sur l'ensemble de vues, consultez la updateméthode sur la façon d'initier le sérialiseur avec un dictionnaire de contexte, qui transmet également l'objet de requête au sérialiseur.

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
la source