django 扩展用户模型

sz81bmfz  于 2022-12-14  发布在  Go
关注(0)|答案(2)|浏览(127)

我正在尝试构建我的第一个Django后端项目,所以我正在尝试创建一个REST API端点,它可以从前端获取用户注册数据并保存在数据库中,如果有效的话。我正在尝试将额外的用户信息保存在一个名为Player的新模型中,并使用一对一字段将其链接到默认的用户模型。
当我从前端接收到包含数据的json文件时,用户模型中创建了一个包含数据的新用户,同时在播放器模型中创建了一个新行,它连接到我们刚刚在用户模型中创建的用户。但问题是字段“height”和“handicap”仍然为空。
我不知道如何将“身高”和“障碍”参数保存到新的Player示例中。
这是我的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

这是我的urls.py文件:

from django.urls import path
from .views import RegistrationView

urlpatterns = [
    path('registration/', RegistrationView.as_view(), name='registration')
]

是否有人知道如何将“身高”和“差点”也保存到播放器模型中?

py49o6xq

py49o6xq1#

您所面临的问题可以通过序列化程序关系来解决,更具体地说,可以通过嵌套关系来解决。
我已经尽我所能地保存了你的代码。尽管如此,一些修改是必要的,或者只是为了让代码更干净而做的。
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”的字段,无需存储相同的信息。另外,第二个函数“保存_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

已创建嵌套在RegistrationSerializer中的PlayerSerializer。通过排除“user”字段来表示“handicap”和“height”字段。
在create方法中,从字典中取出键,使用**kwargs来获得更简洁的格式,然后使用键来更新关系值。
views.py urls.py保持不变。

hsgswve4

hsgswve42#

你在序列化器中创建了用户对象。在下一行中,你尝试从播放器模型中获取用户示例。实际上,那个用户的示例还没有在播放器模型中创建。所以首先你必须在播放器模型中创建那个用户示例。

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

相关问题