使用Django AbstractUser自定义用户模型时出现TypeError: all()缺少self参数
Django自定义用户模型报错:TypeError: all() missing 1 required positional argument: 'self'
问题重现
自定义用户模型代码:
class User(AbstractUser): nickname = models.CharField(max_length=32) birthday = models.DateField() objects = MyUserManager # 问题核心所在 class Meta: ordering = ('-id',)
自定义管理器代码:
class MyUserManager(UserManager): def _create_user(self, username, email, password, **kwargs): if not username: raise ValueError("The given username must be set") user = self.model(email=self.normalize_email(email), **kwargs) user.set_password(password) user.save() return user def create_user(self, username, email=None, password=None, **kwargs): kwargs.setdefault('is_admin', False) return self._create_user(username, email, password, **kwargs) def create_superuser(self, username, email=None, password=None, **kwargs): kwargs.setdefault("is_staff", True) kwargs.setdefault('is_admin', True) return self._create_user(username, email, password, **kwargs)
ViewSet代码:
class UserViewSet(ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializers
触发的错误:
TypeError: all() missing 1 required positional argument: 'self'
错误原因分析
1. 核心错误:模型管理器未实例化
你在User模型中把管理器类直接赋值给了objects,而不是管理器的实例。Django要求模型管理器必须是类的实例才能正常工作,当调用User.objects.all()时,相当于直接调用MyUserManager.all()——用类去调用实例方法,自然会缺少self参数(实例方法的第一个参数必须是类的实例本身)。
2. 原生User.objects是什么?
原生User.objects是django.contrib.auth.models.UserManager的实例,Django会自动为默认用户模型创建这个实例,所以调用all()等方法时,是通过实例调用,不会出现参数缺失问题。
3. MyUserManager的其他潜在问题
除了未实例化的问题,你的管理器还有几处需要修正:
_create_user中的user.save()应改为user.save(using=self._db),确保多数据库环境下使用正确的数据库连接;create_user和create_superuser中使用了is_admin字段,但你的User模型并未定义该字段,AbstractUser默认用is_superuser标识超级用户,这里会导致创建用户时报错;create_superuser缺少对is_superuser的设置,会导致创建的超级用户不具备完整权限。
解决方法
第一步:修正模型的管理器赋值
把objects = MyUserManager改为实例化形式:
class User(AbstractUser): nickname = models.CharField(max_length=32) birthday = models.DateField() objects = MyUserManager() # 添加括号,实例化管理器 class Meta: ordering = ('-id',)
第二步:修正MyUserManager的逻辑
class MyUserManager(UserManager): def _create_user(self, username, email, password, **kwargs): if not username: raise ValueError("The given username must be set") email = self.normalize_email(email) user = self.model(username=username, email=email, **kwargs) user.set_password(password) user.save(using=self._db) # 添加数据库连接参数 return user def create_user(self, username, email=None, password=None, **kwargs): # 改用AbstractUser默认字段,若需is_admin需先在模型中定义 kwargs.setdefault('is_staff', False) kwargs.setdefault('is_superuser', False) return self._create_user(username, email, password, **kwargs) def create_superuser(self, username, email=None, password=None, **kwargs): kwargs.setdefault('is_staff', True) kwargs.setdefault('is_superuser', True) # 若需is_admin字段,先在User模型中添加后再启用下面一行 # kwargs.setdefault('is_admin', True) # 校验超级用户必要字段 if kwargs.get('is_staff') is not True: raise ValueError('Superuser must have is_staff=True.') if kwargs.get('is_superuser') is not True: raise ValueError('Superuser must have is_superuser=True.') return self._create_user(username, email, password, **kwargs)
第三步:同步数据库
修改完成后执行数据库迁移:
python manage.py makemigrations python manage.py migrate
内容的提问来源于stack exchange,提问作者Semin
相关产品推荐
相关产品推荐

