Подтвердить что ты не робот

Как зарегистрировать пользователей в системе Django REST?

Я кодирую REST API с структурой Django REST. API будет основой для мобильного мобильного приложения. После выполнения этого урока я могу сериализовать все мои модели, и я могу создавать новые ресурсы и обновлять их.

Я использую AuthToken для аутентификации.

Мой вопрос:

Как только у меня есть ресурс /users, я хочу, чтобы пользователь приложения мог зарегистрироваться. Итак, лучше ли иметь отдельный ресурс, например /register, или разрешить анонимным пользователям POST до /users нового ресурса?

Кроме того, некоторые рекомендации о разрешениях будут большими.

4b9b3361

Ответ 1

Я пошел вперед и сделал собственное собственное представление для обработки регистрации, так как мой сериализатор не ожидает, чтобы отображать/извлекать пароль. Я сделал URL-адрес отличным от ресурса /users.

Мой url conf:

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

Мой взгляд:

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

Возможно, я ошибаюсь, но вам не нужно ограничивать разрешения для этого представления, так как вам нужны неаутентифицированные запросы...

Ответ 2

Django REST Framework 3 позволяет переопределить метод create в сериализаторах:

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", )

Сериализованные поля для классов, унаследованных от ModelSerializer должны быть явно объявлены в Meta для Django Rest Framework v3.5 и новее.

Файл 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

Ответ 3

Самое простое решение, работающее в 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

Нет необходимости в других изменениях, просто убедитесь, что у пользователей, не прошедших проверку подлинности, есть разрешение на создание нового пользовательского объекта.

write_only_fields будет гарантировать, что пароли (на самом деле: их хэш, который мы храним) не отображаются, тогда как перезаписанный метод create гарантирует, что пароль не сохраняется в ясном тексте, а как хэш.

Ответ 4

Я обновил ответ Cahlan для поддержки пользовательских моделей от Django 1.5 и вернул идентификатор пользователя в ответ.

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)

Ответ 5

Я обычно отношусь к представлению User точно так же, как к любой другой конечной точке API, для которой требуется авторизация, за исключением того, что я просто переопределяю набор разрешений для класса представлений своим собственным для POST (он же create). Я обычно использую этот шаблон:

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

Для примера, вот сериализатор, который я обычно использую с ним:

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

Ответ 6

@cpury выше предлагается с использованием опции write_only_fields. Однако это не сработало для меня в DRF 3.3.3

В DRF 3.0 параметр write_only_fields на ModelSerializer перенесен в PendingDeprecation и в DRF 3.2 заменен более общим extra_kwargs:

extra_kwargs = {'password': {'write_only': True}}

Ответ 7

Все ответы до сих пор создают пользователя, а затем обновляют пароль пользователя. Это приводит к записи двух БД. Чтобы избежать лишней ненужной записи в БД, установите пароль пользователя перед сохранением:

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 password.
        user.set_password(validated_data['password'])
        user.save()
        return user

Ответ 8

Немного поздно для вечеринки, но может помочь кому-то, кто не хочет писать больше строк кода.

Мы можем использовать метод super для достижения этого.

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

Ответ 9

Реализация на основе набора Python 3, Django 2 и Django REST Framework:

Файл: 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',)

Файл 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

Файл urls.py

from rest_framework.routers import DefaultRouter
from .views import CreateUserView

router = DefaultRouter()
router.register(r'createuser', CreateUserView)

urlpatterns = router.urls