Django注册API问题:Player模型height与handicap字段无法保存
问题诊断与修复方案
你的核心问题是Player模型的height和handicap字段无法保存,根源在于信号函数的反向关联错误、User创建逻辑的密码处理问题,以及信号与序列化器的执行顺序冲突。以下是具体修复步骤:
1. 修正models.py中的信号函数与字段默认值
首先解决信号函数中错误的反向关联属性:
from django.db import models from django.core.validators import MaxValueValidator, MinValueValidator from django.contrib.auth.models import User from django.dispatch import receiver from django.db.models.signals import post_save from datetime import datetime class Player(models.Model): def __str__(self): return self.user.username # 可选:设置related_name,让User实例可以通过user.profile访问Player user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') handicap = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(28)]) height = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(250)]) # 修正默认值:去掉括号,确保每次注册都用当前时间 registration_date = models.DateTimeField(default=datetime.now) @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: Player.objects.create(user=instance) @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): # 若设置了related_name='profile',用instance.profile.save();否则用instance.player.save() instance.profile.save()
2. 修复serializers.py中的创建逻辑
主要解决密码明文存储问题,以及优化Player字段的赋值流程:
from rest_framework import serializers from django.contrib.auth.models import User from rest_framework.validators import UniqueValidator from django.contrib.auth.password_validation import validate_password from django.core.validators import MaxValueValidator, MinValueValidator from .models import Player class RegisterSerializer(serializers.ModelSerializer): first_name = serializers.CharField(required=True) last_name = serializers.CharField(required=True) email = serializers.EmailField(required=True, validators=[UniqueValidator(queryset=User.objects.all())]) password = serializers.CharField(write_only=True, required=True, validators=[validate_password]) password2 = serializers.CharField(write_only=True, required=True) height = serializers.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(250)]) handicap = serializers.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(28)]) class Meta: model = User fields = ('first_name', 'last_name', 'email', 'password', 'password2', 'height', 'handicap') def validate(self, attrs): if attrs['password'] != attrs['password2']: raise serializers.ValidationError({'password': "密码不匹配!"}) return attrs def create(self, validated_data): # 提取Player专属字段 player_fields = { 'height': validated_data.pop('height'), 'handicap': validated_data.pop('handicap') } # 创建User实例,用set_password加密密码 user = User.objects.create( username=validated_data['email'], first_name=validated_data['first_name'], last_name=validated_data['last_name'], email=validated_data['email'] ) user.set_password(validated_data['password']) user.save() # 直接创建Player并赋值,避免信号创建后再修改 Player.objects.create(user=user, **player_fields) return user
3. 可选:简化信号逻辑(避免重复操作)
如果已经在序列化器中处理Player的创建,可以移除create_user_profile信号,或者修改为get_or_create避免重复创建:
@receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: Player.objects.get_or_create(user=instance)
验证修复
完成修改后重启服务,发送注册请求,检查数据库中Player表的height和handicap字段是否已正确保存。
内容的提问来源于stack exchange,提问作者dorstr999
相关产品推荐
相关产品推荐

