如何在 DRF 中实现注册新用户功能。
首先应该理解 Django 原有的 流程。DRF 与 Django 的注册流程不同的是:
- Django 有现成的 
UserCreationForm,校验表单中提交的用户名密码信息并实际保存到数据库;DRF 没有,需要自己实现 - Django 的 
<form>中需要带有 csrf token,但 DRF 中不需要带;如果用户在未登陆状态,对它实施 CSRF 攻击意义也不大 
下面的实现上重度参考了 Django: Auth: Signup 中 Django 本身的实现,以及这个 StackOverflow 帖子。实现的重点写在注释中。
Serializer 实现
# app/serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model, password_validation
# get_user_model 可以获得 custom user model
UserModel = get_user_model()
class UserSerializer(serializers.ModelSerializer):
    # password1 及 password2 表示用户在注册表单中,填写的「密码」和「确认密码」两个位置
    # write_only 因为它不需要出现在读接口中
    # input_type 使它在 DRF 的 browsable API 页面中是一个 <input type="password"> 而不是 <input type="text">
    # min_length 及 max_length 是额外的要求,因为 Django 默认只限制密码长度为 128 位,看这里:
    #   django.contrib.auth.base_user.AbstractBaseUser
    password1 = serializers.CharField(
        label="Password", write_only=True, style={'input_type': 'password'},
        min_length=8, max_length=20
    )
    password2 = serializers.CharField(
        label="Password confirmation", write_only=True, style={'input_type': 'password'},
        min_length=8, max_length=20
    )
    def validate_password1(self, value):
        # 生成一个 UserModel 对象传进去,password validation 才可以做密码跟用户名的相似度检查
        password_validation.validate_password(
            value, UserModel(username=self.initial_data['username'], email=self.initial_data['email'])
        )
        return value
    def validate(self, data):
        # 多 field 组合校验,在这里做
        if data['password1'] != data['password2']:
            raise serializers.ValidationError("The two password fields didn't match")
        return data
    def create(self, validated_data):
        user = UserModel.objects.create(
            username=validated_data['username'],
            email=validated_data['email'],
        )
        # set_password 会对明文密码做 hash
        user.set_password(validated_data['password1'])
        user.save()
        return user
    class Meta:
        model = UserModel
        fields = ("id", "username", "email", "password1", "password2")
        extra_kwargs = {
            # Django 默认的 django.contrib.auth.base_user.AbstractBase 对用户名长度限制宽松,这里加强
            'username': {
                'max_length': 16, 'min_length': 6,
                'help_text': 'Required. 6 to 16 characters required. Letters, digits and @/./+/-/_ only.'
            },
            # Django 默认非必填,这里要求必填
            'email': {'required': True},
        }Views 实现
# app/views.py
from django.contrib.auth import get_user_model
from rest_framework import permissions
from rest_framework.generics import CreateAPIView
from app.serializers import UserSerializer
class SignupView(CreateAPIView):
    model = get_user_model()
    permission_classes = [
		    # 使用 AllowAny 使匿名用户也可以注册。
				# DRF 默认的权限会使得匿名用户无法调用 POST 方法。
        permissions.AllowAny
    ]
    serializer_class = UserSerializerUrls 配置
# project/urls.py
from app.views import SignupView
urlpatterns = [
    # ...
    path('signup/', SignupView.as_view(), name='signup'),
]