Geben Sie den aktuellen Benutzer mit Django Rest Framework zurück

71

Ich entwickle derzeit eine API mit Django.

Aber ich würde gerne eine Ansicht erstellen, die den aktuellen Benutzer mit dem folgenden Endpunkt zurückgibt: /users/current/.

Zu diesem Zweck habe ich eine Listenansicht erstellt und das Abfrageset nach dem Benutzer gefiltert, der die Anforderung gestellt hat. Das funktioniert, aber das Ergebnis ist eine Liste, kein einzelnes Objekt. In Kombination mit der Paginierung erscheint das Ergebnis im Vergleich zu anderen Endpunkten viel zu kompliziert und inkonsistent.

Ich habe auch versucht, eine Detailansicht zu erstellen und das Abfrageset zu filtern, aber DRF beschwert sich, dass ich kein pk oder slug angegeben habe.

Hast du irgendeine Idee?

Maxime
quelle

Antworten:

74

Mit so etwas brechen Sie wahrscheinlich am besten aus den allgemeinen Ansichten aus und schreiben die Ansicht selbst.

@api_view(['GET'])
def current_user(request):
    serializer = UserSerializer(request.user)
    return Response(serializer.data)

Sie können das Gleiche auch mit einer klassenbasierten Ansicht wie der folgenden tun ...

class CurrentUserView(APIView):
    def get(self, request):
        serializer = UserSerializer(request.user)
        return Response(serializer.data)

Natürlich müssen Sie auch keinen Serializer verwenden. Sie können auch die benötigten Felder aus der Benutzerinstanz ziehen.

@api_view(['GET'])
def current_user(request):
    user = request.user
    return Response({
        'username': user.username,
        'email': user.email,
        ...
    })

Hoffentlich hilft das.

Tom Christie
quelle
27

Der beste Weg ist, die Kraft von viewsets.ModelViewSetso zu nutzen:

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get_object(self):
        pk = self.kwargs.get('pk')

        if pk == "current":
            return self.request.user

        return super(UserViewSet, self).get_object()

viewsets.ModelViewSetist eine Kombination von mixins.CreateModelMixin+ mixins.RetrieveModelMixin+ mixins.UpdateModelMixin+ mixins.DestroyModelMixin+ mixins.ListModelMixin+ viewsets.GenericViewSet. Wenn Sie nur alle auflisten oder einen bestimmten Benutzer einschließlich der aktuell authentifizierten Benutzer erhalten möchten, müssen Sie ihn einfach so ersetzen

class UserViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
    # ...
Vladimir Prudnikov
quelle
10

Wenn Sie aus irgendeinem Grund das generische Ansichtsset verwenden müssen, können Sie Folgendes tun:

class UserViewSet(viewsets.ModelViewSet):
    model = User
    serializer_class = UserSerializer

    def get_object(self):
        return self.request.user

    def list(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

retrieveDie Methode wird aufgerufen, wenn der Client eine einzelne Instanz mit einem Bezeichner wie einem Primärschlüssel anfordert und /users/10die Abrufmethode normal auslöst. Rufen Sie selbst Anrufe ab get_object. Wenn Sie möchten, dass die Ansicht immer den aktuell verwendeten Wert zurückgibt, können Sie die Methode ändern get_objectund erzwingen list, um ein einzelnes Element anstelle einer Liste zurückzugeben, indem Sie sie aufrufen und darin zurückgeben self.retrieve.

Owais Lone
quelle
9

Ich habe ein ModelViewSet wie folgt verwendet:

class UserViewSet(viewsets.ModelViewSet):
    model = User
    serializer_class = UserSerializer

    def dispatch(self, request, *args, **kwargs):
        if kwargs.get('pk') == 'current' and request.user:
            kwargs['pk'] = request.user.pk

        return super(UserViewSet, self).dispatch(request, *args, **kwargs)
ejb
quelle
1
elb, ich habe versucht, die obige Funktion zu verwenden, aber es scheint, dass dispatch () zu früh ausgeführt wird, dass request.user immer noch anonym ist. Der Benutzer wird zugewiesen, nachdem der Versand ausgeführt wurde. Gibt es eine Alternative dafür?
Mo J. Mughrabi
Dieser funktioniert gut für mich. Sie können geändert werden soll request.userzu request.user.is_authenticated(). Cuz request.userist, AnonymousUserwenn Sie nicht eingeloggt sind.
Greg Wang
3
Funktioniert mit SessionAuthentication. Funktioniert nicht bei Verwendung von TokenAuthentication. request.user ist innerhalb des Versands anonym.
Sudokai
Dies funktioniert nicht mit der Token-Authentifizierung. Wenn die Authentifizierung innerhalb des ersten () Aufrufs erfolgt und dies beim Versand erfolgt, wird die Verwendung niemals authentifiziert.
pjotr_dolphin
9

Anstatt die volle Leistung von ModelViewSet zu nutzen, können Sie Mixins verwenden. Es gibt RetrieveModelMixin, das zum Abrufen eines einzelnen Objekts verwendet wird, genau wie hier erwähnt - http://www.django-rest-framework.org/api-guide/viewsets/#example_3

class UserViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get_object(self):
        return self.request.user

Wenn Sie auch Ihr Modell aktualisieren müssen, fügen Sie einfach UpdateModelMixin hinzu.

ollamh
quelle