#python #django #django-rest-framework
#python #django #django-rest-framework
Вопрос:
Я пытался добавить атрибуты в пользовательский профиль, создав OneToOneField
для пользователя и добавив разные поля. Теперь я запускаю это и вызываю api с приведенным ниже телом. API может быть успешно проанализирован. Пользователь создается в таблице пользователей и таблице профилей пользователей с правильными атрибутами. Однако Django возвращает ошибку AttributeError: Got AttributeError when attempting to get a value for field first_name on serializer UserProfileSerializer
. Это имеет смысл, поскольку модель не имеет этих атрибутов, но каков правильный способ передать json таким же образом и создать пользователя в User
таблице и UserProfile
таблице?
{
"first_name": "Jay",
"last_name" : "Patel",
"email": "tes1t@email.com",
"password": "password",
"tier": "Gold",
"bkms_id": "12234"
}
model.py
# Create your models here.
class UserProfile(models.Model):
MedalType: List[Tuple[str, str]] = [('Bronze', 'Bronze'), ('Silver', 'Silver'), ('Gold', 'Gold')]
bkms_id = models.PositiveIntegerField()
tier = models.CharField(choices=MedalType, max_length=100)
user = models.OneToOneField(to=User, on_delete=models.CASCADE)
def __str__(self):
return self.user.username
serializer.py
from typing import Dict
from django.contrib.auth.models import User
from rest_framework import serializers
from authentication.models import UserProfile
class UserProfileSerializer(serializers.ModelSerializer):
password = serializers.CharField(max_length=65, min_length=8, write_only=True, required=True,
style={'input_type': 'password'})
email = serializers.EmailField(max_length=255, min_length=4, required=True)
first_name = serializers.CharField(max_length=255, min_length=2, required=True)
last_name = serializers.CharField(max_length=255, min_length=2, required=True)
bkms_id = serializers.IntegerField(required=True, min_value=0)
tier = serializers.CharField(required=True)
class Meta:
model = UserProfile
fields = ['first_name', 'last_name', 'email', 'password', 'bkms_id', 'tier']
def validate(self, attrs):
if User.objects.filter(email=attrs.get('email', '')).exists():
raise serializers.ValidationError({'email': 'Email is already in use'})
if UserProfile.objects.filter(bkms_id=attrs.get('bkms_id', '')).exists():
raise serializers.ValidationError({'bkms_id': 'BKMS is already in use'})
return super().validate(attrs)
def create(self, validated_data: Dict):
email = validated_data.pop('email', '')
password = validated_data.pop('password', '')
first_name = validated_data.pop('first_name', '')
last_name = validated_data.pop('last_name', '')
user = User.objects.create_user(email, email, password, first_name=first_name, last_name=last_name)
user.save()
validated_data['user'] = user
return UserProfile.objects.create(**validated_data)
views.py
# Create your views here.
from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from authentication.serializers import UserProfileSerializer
class RegisterView(GenericAPIView):
serializer_class = UserProfileSerializer
permission_classes = [AllowAny]
def post(self, request):
serializer = UserProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Ответ №1:
Я бы предложил создать разные сериализаторы, подобные этому:
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(max_length=65, min_length=8, write_only=True, required=True,
style={'input_type': 'password'})
email = serializers.EmailField(max_length=255, min_length=4, required=True)
first_name = serializers.CharField(max_length=255, min_length=2, required=True)
last_name = serializers.CharField(max_length=255, min_length=2, required=True)
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password']
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
bkms_id = serializers.IntegerField(required=True, min_value=0)
tier = serializers.CharField(required=True)
class Meta:
model = UserProfile
fields = ['user', 'bkms_id', 'tier']
def validate(self, attrs):
if User.objects.filter(email=attrs.get('email', '')).exists():
raise serializers.ValidationError({'email': 'Email is already in use'})
if UserProfile.objects.filter(bkms_id=attrs.get('bkms_id', '')).exists():
raise serializers.ValidationError({'bkms_id': 'BKMS is already in use'})
attrs['user'] = {
'email': attrs.get('email', ''),
'first_name': attrs.get('first_name', ''),
'last_name': attrs.get('last_name', ''),
'password': attrs.get('password', '')
}
return super().validate(attrs)
def create(self, validated_data: Dict):
validated_user = validated_data.pop('user', {})
email = validated_user.pop('email', '')
password = validated_user.pop('password', '')
first_name = validated_user.pop('first_name', '')
last_name = validated_user.pop('last_name', '')
user = User.objects.create_user(email=email, password=password, first_name=first_name, last_name=last_name)
user.save()
validated_data['user'] = user
return UserProfile.objects.create(**validated_data)