如何在Django REST框架中注册用户?
我使用Django REST框架编写了一个REST API。 该API将成为社交移动应用程序的后端。 遵循教程后,我可以序列化所有模型,并可以创build新资源并进行更新。
我正在使用AuthToken进行身份validation。
我的问题是:
一旦我有/users
资源,我希望应用程序用户能够注册。 那么,拥有一个像/register
这样的独立资源还是允许匿名用户向/users
一个新资源会更好?
另外,一些关于权限的指导会很好。
我继续做了我自己的自定义视图来处理注册,因为我的序列化程序不期望显示/检索密码。 我做了不同于/用户资源的url。
我的urlconf:
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)
我可能是错的,但似乎并不需要限制这个视图的权限,因为你想要未经身份validation的请求…
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
另外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
最简单的解决scheme,使用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
不需要进行其他更改,只需确保未经身份validation的用户有权创build新的用户对象。
write_only_fields
将确保密码(实际上是:我们存储的哈希)不被显示,而覆盖的create
方法确保密码不是以明文forms存储,而是以散列forms存储。
我更新了Cahlan的答案,以支持来自Django 1.5的自定义用户模型,并在响应中返回用户的ID。
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)
我通常对待用户视图就像任何其他需要授权的API端点,除非我只是用我自己的POST(又名创build)覆盖视图类的权限集。 我通常使用这种模式:
from django.contrib.auth import get_user_model from rest_framework import viewsets 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
上面的@cpurybuild议使用write_only_fields
选项。 然而,这在3.3.3的DRF中并不适用
在DRF 3.0中 , write_only_fields
上的write_only_fields
选项已被移至PendingDeprecation,并在DRF 3.2中被replace为更通用的extra_kwargs:
extra_kwargs = {'password': {'write_only': True}}
到目前为止所有的答案创build用户,然后更新用户的密码。 这导致了两个数据库写入。 为避免多余的数据库写入,请在保存之前设置用户的密码:
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
晚会有点晚,但可能会帮助不想写更多行代码的人。
我们可以使用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