104 votes

Comment enregistrer les utilisateurs dans le cadre REST de Django ?

Je suis en train de coder une API REST avec Cadre REST de Django . L'API sera le backend d'une application mobile sociale. Après avoir suivi le tutoriel, je peux sérialiser tous mes modèles et je suis capable de créer de nouvelles ressources et de les mettre à jour.

J'utilise AuthToken pour l'authentification.

Ma question est la suivante :

Une fois que j'ai le /users ressource, je veux que l'utilisateur de l'application puisse s'enregistrer. Donc, est-il préférable d'avoir une ressource séparée comme /register ou permettre à des utilisateurs anonymes de POSTER à /users une nouvelle ressource ?

De même, des conseils sur les autorisations seraient les bienvenus.

122voto

Maxim Dunaevsky Points 18

Cadre REST de Django 3 permettre contourner create dans les sérialiseurs :

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_user(
            username=validated_data['username'],
            password=validated_data['password'],
        )

        return user

    class Meta:
        model = UserModel
        # Tuple of serialized model fields (see link [2])
        fields = ( "id", "username", "password", )

Champs sérialisés pour les classes héritées de ModelSerializer doit être déclarée de manière patente dans Meta pour Django Rest Framework v3.5 et le plus récent.

Fichier 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

54voto

Cahlan Sharp Points 751

J'ai pris les devants et créé ma propre vue personnalisée pour gérer l'enregistrement puisque mon sérialiseur ne s'attend pas à afficher/récupérer le mot de passe. J'ai fait en sorte que l'url soit différente de celle de la ressource /users.

Mon url conf :

url(r'^users/register', 'myapp.views.create_auth'),

Mon avis :

@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)

Je peux me tromper, mais il ne semble pas que vous ayez besoin de limiter les permissions sur cette vue puisque vous voulez des requêtes non authentifiées...

50voto

cpury Points 634

La solution la plus simple, fonctionnant en DRF 3.x :

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

Pas besoin d'autres changements, assurez-vous simplement que les utilisateurs non authentifiés ont la permission de créer un nouvel objet utilisateur.

write_only_fields s'assurera que les mots de passe (en fait : leur hachage que nous stockons) ne sont pas affichés, tandis que l'option écrasée create garantit que le mot de passe n'est pas stocké en texte clair, mais sous forme de hachage.

42voto

digitalfoo Points 1076

En général, je traite la vue Utilisateur comme n'importe quel autre point de terminaison d'API nécessitant une autorisation, sauf que je remplace l'ensemble de permissions de la classe de vue par les miennes pour le POST (c'est-à-dire la création). J'utilise généralement ce modèle :

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()

Pour faire bonne mesure, voici le sérialiseur que j'utilise généralement avec lui :

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

27voto

Chris Points 371

J'ai mis à jour la réponse de Cahlan pour prendre en charge les modèles d'utilisateur personnalisés de Django 1.5 et renvoyer l'ID de l'utilisateur dans la réponse.

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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X