Как зарегистрировать пользователей в системе Django REST?
Я кодирую REST API с структурой Django REST. API будет основой для мобильного мобильного приложения. После выполнения этого урока я могу сериализовать все мои модели, и я могу создавать новые ресурсы и обновлять их.
Я использую AuthToken для аутентификации.
Мой вопрос:
Как только у меня есть ресурс /users
, я хочу, чтобы пользователь приложения мог зарегистрироваться. Итак, лучше ли иметь отдельный ресурс, например /register
, или разрешить анонимным пользователям POST до /users
нового ресурса?
Кроме того, некоторые рекомендации о разрешениях будут большими.
Ответы
Ответ 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