Django REST Framework自定义用户注册遇KeyError问题求助
嘿,我来帮你搞定这个DRF用户注册的坑!
你现在遇到的KeyError,大概率是因为用OneToOneField关联默认User和自定义CustomUser的方式,在注册流程里没处理好两个模型的创建顺序,或者序列化器没有把请求数据正确分配到对应模型的字段上。而且这种“外挂式”扩展用户模型的方式,其实并不是Django官方推荐的最佳实践哦。
AbstractUser自定义用户模型 Django更建议通过继承AbstractUser来扩展用户模型,这样所有字段都在同一个模型里,注册时只需要处理一个模型,逻辑更简单,也能从根源避免OneToOne关联带来的各种问题。
1. 调整CustomUser模型
把原来的OneToOne关联改成直接继承AbstractUser,新增birthday字段:
from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): # 允许为空可以降低注册门槛,根据你的业务需求调整 birthday = models.DateField(null=True, blank=True) # 可选:如果想用邮箱作为登录标识,可添加以下配置 # USERNAME_FIELD = 'email' # REQUIRED_FIELDS = ['username']
然后一定要在settings.py里配置默认用户模型:
# 替换成你的app名称,比如'app_name.CustomUser' AUTH_USER_MODEL = '你的应用名.CustomUser'
注意:如果项目已经执行过数据库迁移,修改这个配置可能需要清空数据库或做数据迁移,建议在项目初期就设置好自定义用户模型。
2. 编写对应序列化器
直接基于CustomUser编写序列化器,不用再处理两个模型的关联逻辑:
from rest_framework import serializers from .models import CustomUser class CustomUserSerializer(serializers.ModelSerializer): # 注册时需要确认密码,新增password2字段 password2 = serializers.CharField(write_only=True) class Meta: model = CustomUser fields = ('username', 'email', 'birthday', 'password', 'password2') extra_kwargs = { 'password': {'write_only': True} } def validate(self, attrs): # 验证两次输入的密码是否一致 if attrs['password'] != attrs['password2']: raise serializers.ValidationError("两次输入的密码不匹配") return attrs def create(self, validated_data): # 移除多余的password2字段,用create_user创建用户(自动哈希密码) validated_data.pop('password2') user = CustomUser.objects.create_user(**validated_data) return user
3. 编写注册视图
用DRF的CreateAPIView快速实现注册接口:
from rest_framework import generics from .serializers import CustomUserSerializer class UserRegistrationView(generics.CreateAPIView): serializer_class = CustomUserSerializer
最后在urls.py里配置路由:
from django.urls import path from .views import UserRegistrationView urlpatterns = [ path('register/', UserRegistrationView.as_view(), name='user-registration'), ]
如果因为特殊需求必须保留原来的OneToOne结构,那你需要在序列化器的create方法里严格控制创建顺序:先创建User实例,再用它关联创建CustomUser,同时要确保字段映射正确:
from rest_framework import serializers from django.contrib.auth.models import User from .models import CustomUser class CustomUserSerializer(serializers.ModelSerializer): # 显式映射User模型的字段 username = serializers.CharField(source='user.username') email = serializers.EmailField(source='user.email') password = serializers.CharField(source='user.password', write_only=True) class Meta: model = CustomUser fields = ('username', 'email', 'password', 'birthday') def create(self, validated_data): # 先提取User模型的数据 user_data = validated_data.pop('user') # 用create_user创建User(自动哈希密码) user = User.objects.create_user(**user_data) # 关联User创建CustomUser custom_user = CustomUser.objects.create(user=user, **validated_data) return custom_user
这种方式很容易因为前端传参和序列化器字段不匹配触发KeyError,一定要确保请求参数名和序列化器定义的字段名完全对应。
优先推荐用AbstractUser的方式,这是Django官方的最佳实践,能避免很多关联逻辑带来的问题,注册流程也更清晰。按照上面的方法调整后,应该就能解决你遇到的KeyError啦。
内容的提问来源于stack exchange,提问作者Adrian

