如何在Django Rest Framework中为继承User模型的Player添加Token?
我来帮你解决这个问题,先拆解下错误根源,再给出两种可行的解决方案。
错误原因解析
你遇到的TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use groups.set() instead.,核心问题出在**调用Player.objects.create_user(**validated_data)**这一步。
create_user是Django AbstractUser自带的UserManager提供的方法,但你的Player作为自定义MyUser的子类,默认使用的是普通的models.Manager,它没有处理groups、user_permissions这类多对多字段的逻辑,直接调用create_user就会触发多对多字段的赋值错误。
另外补充说明:Django REST Framework的Token模型是关联到你配置的AUTH_USER_MODEL(也就是你的MyUser)的,而Player是MyUser的单表继承子类,本质上属于MyUser实例,所以Token关联player是完全可行的,只是创建Player的方式需要调整。
方案一:手动处理密码哈希,直接创建Player
这种方法不需要修改模型结构,直接在Serializer里手动处理密码哈希,用create方法创建Player实例:
from django.contrib.auth.hashers import make_password from rest_framework.authtoken.models import Token class PlayerSerializer(serializers.ModelSerializer): class Meta: model = Player fields = '__all__' # 建议将password设为只写字段,避免接口返回明文密码 extra_kwargs = {'password': {'write_only': True, 'required': True}} def create(self, validated_data): # 从验证数据中取出密码 password = validated_data.pop('password') # 创建Player实例 player = Player.objects.create(**validated_data) # 手动对密码进行哈希处理后保存 player.password = make_password(password) player.save() # 为该Player创建并关联Token Token.objects.create(user=player) return player
方案二:为自定义用户模型添加管理器,复用create_user逻辑
如果你想沿用create_user的自动处理逻辑(它会自动哈希密码、设置默认用户状态等),可以给MyUser指定UserManager,让Player继承这个管理器:
首先修改你的模型代码:
from django.contrib.auth.models import AbstractUser, UserManager class MyUserManager(UserManager): pass class MyUser(AbstractUser): # 为自定义用户模型配置UserManager objects = MyUserManager() pass class Player(MyUser): national_id = models.CharField(max_length=10) # 继承父类的UserManager objects = MyUserManager() def save(self, *args, **kwargs): self.username = self.email return super().save(*args, **kwargs)
然后更新Serializer代码:
from rest_framework.authtoken.models import Token class PlayerSerializer(serializers.ModelSerializer): class Meta: model = Player fields = '__all__' extra_kwargs = {'password': {'write_only': True, 'required': True}} def create(self, validated_data): # 现在可以安全调用create_user方法 player = Player.objects.create_user(**validated_data) # 创建关联的Token Token.objects.create(user=player) return player
这两种方案都能完美解决你的问题,第一种更直接快速,第二种更贴合Django用户模型的设计规范,你可以根据项目需求选择合适的方式。
内容的提问来源于stack exchange,提问作者uber

