使用Django Rest Framework注册用户时触发TypeError报错求助
Django DRF 用户注册 TypeError 问题解决
问题描述
我是Django和DRF新手,使用Postman注册新用户时遇到如下报错:
调用`User.objects.create()`时触发TypeError。这可能是因为你的序列化器类中有一个可写字段,它不是`User.objects.create()`的有效参数。你可能需要将该字段设为只读,或者重写UserRegistrationSerializer.create()方法来正确处理这个问题。
我跟随教程编写代码,但教程中的代码可正常运行,我却卡在此问题数小时,希望有人能解释报错原因。以下是我的代码:
serializers.py
from rest_framework import serializers from account.models import User class UserRegistrationSerializer(serializers.ModelSerializer): password2 = serializers.CharField(style={'input_type':'password'},write_only=True) class Meta: model = User fields = ['email','name','password','password2','tc'] extra_kwargs = { 'password':{'write_only':True} } # validating Password and confirm password while Registration def validate(self,attrs): password = attrs.get('password') password2 = attrs.get('password2') if password != password2: raise serializers.ValidationError("Password and confirm password doesn't match") return attrs def create(self,validate_data): print(validate_data); return User.objects.create_user(**validate_data);
Models.py
from django.db import models from django.contrib.auth.models import BaseUserManager, AbstractBaseUser # Custom User Manager class UserManager(BaseUserManager): def create_user(self, email, name,tc, password=None,password2=None): """ Creates and saves a User with the given email, name, tc and password. """ if not email: raise ValueError('Users must have an email address') user = self.model( email=self.normalize_email(email), name = name, tc = tc, ) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, name,tc, password=None): """ Creates and saves a superuser with the given email, name, tc and password. """ user = self.create_user( email, password=password, name=name, tc=tc, ) user.is_admin = True user.save(using=self._db) return user # Custom user model class User(AbstractBaseUser): email = models.EmailField( verbose_name='Email', max_length=255, unique=True, ) name = models.CharField(max_length=200) tc = models.BooleanField() is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['name','tc'] def __str__(self): return self.email def has_perm(self, perm, obj=None): "Does the user have a specific permission?" # Simplest possible answer: Yes, always return self.is_admin def has_module_perms(self, app_label): "Does the user have permissions to view the app `app_label`?" # Simplest possible answer: Yes, always return True @property def is_staff(self): "Is the user a member of staff?" # Simplest possible answer: All admins are staff return self.is_admin
views.py
from rest_framework.response import Response from rest_framework import status from rest_framework.views import APIView from account.serializers import UserRegistrationSerializer class UserRegistrationView(APIView): def post(self,request,format=None): serializer = UserRegistrationSerializer( data = request.data); print("******************************************") print(request.data); if serializer.is_valid(raise_exception=True): user = serializer.save() return Response({'msg':'Registration Sucssess'},status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
报错原因分析
- 缩进错误导致重写方法失效:你的
validate和create方法被错误地缩进在Meta类内部,DRF无法识别这些重写方法,会默认调用ModelSerializer的create方法——该方法直接调用User.objects.create(),但password2不是User模型的字段,因此触发TypeError。 - 无效参数传递:即使修正缩进,
create方法中把包含password2的完整validate_data传给create_user也会有问题,因为create_user方法不需要password2参数(它仅用于前端验证,模型和创建逻辑都不需要这个字段)。
解决方案
步骤1:修正缩进并移除无效字段
修改serializers.py,将validate和create方法移到Meta类外部,并在create方法中移除password2字段:
from rest_framework import serializers from account.models import User class UserRegistrationSerializer(serializers.ModelSerializer): password2 = serializers.CharField(style={'input_type':'password'}, write_only=True) class Meta: model = User fields = ['email','name','password','password2','tc'] extra_kwargs = { 'password':{'write_only':True} } # 验证密码和确认密码是否一致 def validate(self, attrs): password = attrs.get('password') password2 = attrs.get('password2') if password != password2: raise serializers.ValidationError("密码和确认密码不匹配") return attrs def create(self, validate_data): # 移除不需要的password2字段 validate_data.pop('password2') return User.objects.create_user(**validate_data)
步骤2:验证逻辑
validate方法已经完成了密码一致性校验,password2完成使命后无需再传入用户创建方法。- 修正缩进后,DRF会使用你重写的
create方法,而非默认逻辑,避免调用User.objects.create()时传入无效字段。
完成上述修改后,重新用Postman测试注册接口即可正常运行。
内容的提问来源于stack exchange,提问作者sushant aryal
相关产品推荐
相关产品推荐

