我试图构建我的第一个Django后端项目,所以我试图创建一个REST API端点,从前端获取json文件中的用户注册数据,并将其保存在数据库中,如果它是有效的。我试图将额外的用户信息保存在一个名为Player的新模型中,并使用一对一字段将其链接到默认的user模型。
当我收到json文件与数据从前端的一个新用户的数据是在用户模型中创建的,也在玩家模型中创建了一个新的行,连接到我们刚刚在用户模型中创建的用户。但问题是字段的"高度"one_answers";handicap"仍然是空着的。
我不知道如何保存"height"one_answers";handicap">
这是我的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 *
# This model extend the basic built-in User model, by adding additional information on the uesr like
# handicap score anf height.
class Player(models.Model):
def __str__(self):
return self.user.username
user = models.OneToOneField(User, on_delete=models.CASCADE) # connecting this model to the User model
# (cascade means when deleting a user row in the user table
# the match row in this table will automatically will be deleted)
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())
#a listener that listen to the User model, if a new user as been save, it creates a new row in the player model with the new user in the user field
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created: # if a new user created in the User model
Player.objects.create(user=instance) # creating a new row in player, inserting the new user instance to the user field
# if a User is saved we update the user instance to the player user field
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
这是我的serializers.py文件:
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 serializer that handel the data from user registration
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())]) # making sure that the email that the user entered have not being used by another user
password = serializers.CharField(write_only=True, required=True, validators=[validate_password]) # checking that the password is valid
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: # nested class that gives the serializer details
model = User
fields = ('first_name', 'last_name', 'email', 'password', 'password2', 'height', 'handicap')
# overriding the built-in validation method of the model serializer
def validate(self, attrs):
if attrs['password'] != attrs['password2']: # if the 2 passwords on the form don't match
raise serializers.ValidationError({'password': "passwords don't match!"}) # raising an error
return attrs
# overriding the built-in create method
def create(self, validated_data):
# creating a user instance with the data came from the registration
user = User.objects.create(username=validated_data['email'], first_name=validated_data['first_name'], last_name=validated_data['last_name'], email=validated_data['email'], password=validated_data['password'])
user.save() # saving the user registration data to the database
player = Player.objects.get(user=user)
player.height = validated_data['height']
player.handicap = validated_data['handicap']
player.save()
return user
这是我的views.py文件:
from rest_framework import generics
from .serializers import *
# Create your views here.
class RegistrationView(generics.CreateAPIView):
queryset = User.objects.all()
serializer_class = RegisterSerializer
我的url .py文件:
from django.urls import path
from .views import RegistrationView
urlpatterns = [
path('registration/', RegistrationView.as_view(), name='registration')
]
有人知道怎么做才能保存"height"one_answers";handicap"玩家模型?
您所面临的问题可以通过序列化器关系来解决,更具体地说是通过嵌套关系来解决。
我已经尽力保存你的代码。虽然,一些更改是必要的,或者只是为了使代码更清晰。
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
class Player(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
handicap = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(28)])
height = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(250)])
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Player.objects.create(user=instance)
def __str__(self):
return self.user.username
删除'registration_date'字段。抽象用户模型已经有一个名为"date_joined"的字段,不需要存储相同的信息。另外,第二个函数'save_user_profile '也不是必需的。
serializers.py
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 core.models import Player
class PlayerSerializer(serializers.ModelSerializer):
height = serializers.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(250)])
handicap = serializers.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(28)])
class Meta:
model = Player
exclude = ['user']
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)
player = PlayerSerializer()
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password', 'password2', 'player')
def validate(self, attrs):
if attrs['password'] != attrs['password2']:
raise serializers.ValidationError({'password': "passwords don't match!"})
return attrs
def create(self, validated_data):
pw2 = validated_data.pop('password2')
player = validated_data.pop('player')
user = User.objects.create(**validated_data)
user.player.height = player['height']
user.player.handicap = player['handicap']
user.player.save()
return user
创建一个PlayerSerializer嵌套在RegistrationSerializer中。通过排除'user'字段来表示'handicap'和'height'字段。
在create方法上,将键从字典中弹出以使用**kwargs以获得更干净的格式。稍后,使用键来更新关系值。
views.py和urls.py保持不变。
您在序列化器中创建了用户对象。在下一行中,您将尝试从Player模型中获取用户实例。实际上那个用户的实例还没有在玩家模型中创建。首先你必须在Player模型中创建那个用户实例。
def create(self, validated_data):
# first, get the data for player model from validated data
height = validated_data.pop.get('height')
handicap = validated_data.pop.get('handicap')
# now create the user
user = User.objects.create(**validated_data)
# now using the user instance, create the player object for that user.
Player.objects.create(user=user, height=height, handicap=handicap)
return user