Ich codiere eine REST-API mit dem Django REST-Framework . Die API wird das Backend einer Social Mobile App sein. Nachdem ich dem Tutorial gefolgt bin, kann ich alle meine Modelle serialisieren und neue Ressourcen erstellen und aktualisieren.
Ich verwende AuthToken zur Authentifizierung.
Meine Frage ist:
Sobald ich die /users
Ressource habe, möchte ich, dass sich der App-Benutzer registrieren kann. Ist es also besser, eine separate Ressource zu haben /register
oder anonymen Benutzern zu erlauben, auf /users
eine neue Ressource zu posten ?
Außerdem wäre eine Anleitung zu Berechtigungen großartig.
Antworten:
Ich habe meine eigene benutzerdefinierte Ansicht für die Registrierung erstellt, da mein Serializer nicht erwartet, dass das Kennwort angezeigt / abgerufen wird. Ich habe die URL von der Ressource / users unterschieden.
Meine URL conf:
url(r'^users/register', 'myapp.views.create_auth'),
Meine Sicht:
@api_view(['POST']) def create_auth(request): serialized = UserSerializer(data=request.DATA) if serialized.is_valid(): User.objects.create_user( serialized.init_data['email'], serialized.init_data['username'], serialized.init_data['password'] ) return Response(serialized.data, status=status.HTTP_201_CREATED) else: return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST)
Ich kann mich irren, aber es scheint nicht so, als müssten Sie die Berechtigungen für diese Ansicht einschränken, da Sie nicht authentifizierte Anforderungen wünschen ...
quelle
UserSerializer
keine Passwörter liest / schreibt. Nach dem Anrufis_valid()
ist es in Ordnung, wenn jemand verwenden möchteserialized.data['email']
undserialized.data['username']
das Passwort nur in verfügbar istserialized.init_data['password']
. Auch die Reihenfolge der E-Mail- und Benutzernamenparameter sollte geändert werden (zumindest in Django 1.6). oder Sie können immer benannte Parameter übergeben, zBUser.objects.create_user(email='[email protected]', username='admin', password='admin123')
Django REST Framework 3 ermöglicht die Überschreibungsmethode
create
in Serialisierern:from rest_framework import serializers from django.contrib.auth import get_user_model # If used custom user model UserModel = get_user_model() class UserSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True) def create(self, validated_data): user = UserModel.objects.create( username=validated_data['username'] ) user.set_password(validated_data['password']) user.save() return user class Meta: model = UserModel # Tuple of serialized model fields (see link [2]) fields = ( "id", "username", "password", )
Serialisierte Felder für Klassen, von denen geerbt wurde,
ModelSerializer
müssenMeta
für Django Rest Framework v3.5 und die neueste Version offen deklariert werden .Datei api.py :
from rest_framework import permissions from rest_framework.generics import CreateAPIView from django.contrib.auth import get_user_model # If used custom user model from .serializers import UserSerializer class CreateUserView(CreateAPIView): model = get_user_model() permission_classes = [ permissions.AllowAny # Or anon users can't register ] serializer_class = UserSerializer
quelle
Die einfachste Lösung, die in DRF 3.x funktioniert:
class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('id', 'username', 'password', 'email', 'first_name', 'last_name') write_only_fields = ('password',) read_only_fields = ('id',) def create(self, validated_data): user = User.objects.create( username=validated_data['username'], email=validated_data['email'], first_name=validated_data['first_name'], last_name=validated_data['last_name'] ) user.set_password(validated_data['password']) user.save() return user
Es sind keine weiteren Änderungen erforderlich. Stellen Sie lediglich sicher, dass nicht authentifizierte Benutzer die Berechtigung zum Erstellen eines neuen Benutzerobjekts haben.
write_only_fields
stellt sicher, dass Passwörter (tatsächlich: ihr von uns gespeicherter Hash) nicht angezeigt werden, während die überschriebenecreate
Methode sicherstellt, dass das Passwort nicht im Klartext, sondern als Hash gespeichert wird.quelle
create
Methode hinzufügt, ist die Django-nativeset_password
Methode zum Generieren eines Hashs für das Kennwort.Normalerweise behandle ich die Benutzeransicht wie jeden anderen API-Endpunkt, für den eine Autorisierung erforderlich ist, außer dass ich nur den Berechtigungssatz der Ansichtsklasse mit meinem eigenen für POST (auch bekannt als create) überschreibe. Ich benutze normalerweise dieses Muster:
from django.contrib.auth import get_user_model from rest_framework import viewsets from rest_framework.permissions import AllowAny class UserViewSet(viewsets.ModelViewSet): queryset = get_user_model().objects serializer_class = UserSerializer def get_permissions(self): if self.request.method == 'POST': self.permission_classes = (AllowAny,) return super(UserViewSet, self).get_permissions()
Hier ist der Serializer, den ich normalerweise verwende:
class UserSerializer(serializers.ModelSerializer): class Meta: model = get_user_model() fields = ( 'id', 'username', 'password', 'email', ..., ) extra_kwargs = { 'password': {'write_only': True}, } def create(self, validated_data): user = get_user_model().objects.create_user(**validated_data) return user def update(self, instance, validated_data): if 'password' in validated_data: password = validated_data.pop('password') instance.set_password(password) return super(UserSerializer, self).update(instance, validated_data)
djangorestframework 3.3.x / Django 1.8.x.
quelle
Ich habe Cahlans Antwort aktualisiert, um benutzerdefinierte Benutzermodelle von Django 1.5 zu unterstützen, und die Benutzer-ID in der Antwort zurückgegeben.
from django.contrib.auth import get_user_model from rest_framework import status, serializers from rest_framework.decorators import api_view from rest_framework.response import Response class UserSerializer(serializers.ModelSerializer): class Meta: model = get_user_model() @api_view(['POST']) def register(request): VALID_USER_FIELDS = [f.name for f in get_user_model()._meta.fields] DEFAULTS = { # you can define any defaults that you would like for the user, here } serialized = UserSerializer(data=request.DATA) if serialized.is_valid(): user_data = {field: data for (field, data) in request.DATA.items() if field in VALID_USER_FIELDS} user_data.update(DEFAULTS) user = get_user_model().objects.create_user( **user_data ) return Response(UserSerializer(instance=user).data, status=status.HTTP_201_CREATED) else: return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST)
quelle
is_superuser
undis_staff
Werten. Zulässige Felder sollten explizit IMO angegeben werden, wie in den anderen Beispielen gezeigt.@cpury oben vorgeschlagen mit
write_only_fields
Option. Dies hat jedoch in DRF 3.3.3 bei mir nicht funktioniertIn DRF 3.0 wurde die
write_only_fields
Option in ModelSerializer nach PendingDeprecation verschoben und in DRF 3.2 durch ein allgemeineres extra_kwargs ersetzt:extra_kwargs = {'password': {'write_only': True}}
quelle
Alle bisherigen Antworten erstellen den Benutzer und aktualisieren dann das Kennwort des Benutzers. Dies führt zu zwei DB-Schreibvorgängen. Um ein zusätzliches unnötiges Schreiben der Datenbank zu vermeiden, legen Sie das Kennwort des Benutzers fest, bevor Sie es speichern:
from rest_framework.serializers import ModelSerializer class UserSerializer(ModelSerializer): class Meta: model = User def create(self, validated_data): user = User(**validated_data) # Hash the user's password. user.set_password(validated_data['password']) user.save() return user
quelle
Ein bisschen zu spät zur Party, könnte aber jemandem helfen, der nicht mehr Codezeilen schreiben möchte.
Wir können die
super
Methode verwenden, um dies zu erreichen.class UserSerializer(serializers.ModelSerializer): password = serializers.CharField( write_only=True, ) class Meta: model = User fields = ('password', 'username', 'first_name', 'last_name',) def create(self, validated_data): user = super(UserSerializer, self).create(validated_data) if 'password' in validated_data: user.set_password(validated_data['password']) user.save() return user
quelle
Eine auf Viewset basierende Implementierung von Python 3, Django 2 und Django REST Framework:
Datei: serializers.py
from rest_framework.serializers import ModelSerializers from django.contrib.auth import get_user_model UserModel = get_user_model() class UserSerializer(ModelSerializer): password = serializers.CharField(write_only=True) def create(self, validated_data): user = UserModel.objects.create_user( username=validated_data['username'], password=validated_data['password'], first_name=validated_data['first_name'], last_name=validated_data['last_name'], ) return user class Meta: model = UserModel fields = ('password', 'username', 'first_name', 'last_name',)
Datei views.py :
from rest_framework.viewsets import GenericViewSet from rest_framework.mixins import CreateModelMixin from django.contrib.auth import get_user_model from .serializers import UserSerializer class CreateUserView(CreateModelMixin, GenericViewSet): queryset = get_user_model().objects.all() serializer_class = UserSerializer
Datei urls.py
from rest_framework.routers import DefaultRouter from .views import CreateUserView router = DefaultRouter() router.register(r'createuser', CreateUserView) urlpatterns = router.urls
quelle