Jak uzyskać Request.User w serializatorze Django-Rest-Framework?


124

Próbowałem czegoś takiego, to nie działa.

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

Potrzebuję sposobu uzyskania dostępu do request.user z mojej klasy Serializer.


DRF CurrentUserDefaultjest absolutnie ❤️ django-rest-framework.org/api-guide/validators/ ...
andilabs

Odpowiedzi:


231

Nie możesz uzyskać request.userbezpośredniego dostępu do . Musisz uzyskać dostęp do obiektu żądania, a następnie pobrać atrybut użytkownika.

Lubię to:

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

Albo żeby być bardziej bezpiecznym,

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

Więcej na temat dodatkowego kontekstu można przeczytać tutaj


1
jest napisaneNameError: name 'self' is not defined
Coderaemon

oczywiście miało to miejsce w kontekście zajęć. Najprawdopodobniej nie jesteś w kontekście zajęć
karthikr

3
W moim serializatorze, w validate()metodzie self.context jest pustym dyktando. Czemu?
David D.

14
David - prawdopodobnie rozwiązałeś to dawno temu, ale jeśli ktokolwiek ma ten problem, może to być spowodowane tym, że tworzysz swój serializator ręcznie. Miałem ten problem w zagnieżdżonym serializatorze utworzonym dla ogólnej relacji. Dokumenty mówią, aby zrobić serializer = NoteSerializer (wartość), ale to przekaże tylko twoją instancję, a nie kontekst zawierający żądanie. Można przekazać kwargs do konstruktora i wysłać go potrzebuje info (patrz get_serializer lub GenericAPIView dla jak to robi)
Jon Vaughan

2
@JonVaughan jakiekolwiek szczegóły dotyczące przekazywania kwargs do instancji serializatora?
tyan

74

Właściwie nie musisz zawracać sobie głowy kontekstem. Jest na to znacznie lepszy sposób:

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
To nie zadziałało, zwracając obiekt zerowy. user_edit = serializers.CurrentUserDefault ()
Enderson Menezes

39

Jak Igor wspomniał w innej odpowiedzi, użyj może użyć CurrentUserDefault. Jeśli nie chcesz zastępować metody save tylko w tym celu, użyj doc :

from rest_framework import serializers

class PostSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
    class Meta:
        model = Post

link do dokumentu jest teraz błędnie powiązany.
coler-j

Link do oficjalnej dokumentacji DRF z tym samym przykładem django-rest-framework.org/api-guide/serializers/…
Paolo Melchiorre

2

Możesz przejść request.user, dzwoniąc .save(...)w widoku:

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)

Oto model:

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

Potrzebujesz małej edycji w swoim serializatorze:

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

Oto przykład użycia zestawów widoków mieszania modelu. W createmetodzie można znaleźć właściwy sposób wywołania serializatora. get_serializer poprawnie wypełnia słownik kontekstu. Jeśli potrzebujesz użyć innego serializatora, który jest następnie zdefiniowany w zestawie widoków, zapoznaj się z updatemetodą inicjowania serializatora ze słownikiem kontekstowym, który również przekazuje obiekt żądania do serializatora.

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)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.