You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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关联(不推荐)

如果因为特殊需求必须保留原来的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:13:34