Marco de descanso de Django AttributeError: Got Attribute Error al intentar obtener un valor para el campo

He estado intentando añadir atributos al UserProfile creando un OneToOneField a Usuario y agregando diferentes campos. Ahora corro esto y llamo al api con el cuerpo abajo. El api es capaz de ser analizado con éxito. Un usuario se crea en la tabla de usuario y la tabla de perfil de usuario con los atributos correctos. Sin embargo, Django devuelve un error AttributeError: Got AttributeError when attempting to get a value for field first_name on serializer UserProfileSerializer. Esto tiene sentido ya que el modelo no tiene estos atributos, pero cuál es la manera correcta de pasar el json de la misma manera y crear el usuario en el User Cuadro y UserProfile ¿Mesa?

{
    "first_name": "Jay",
    "last_name" : "Patel",
    "email": "[email protected]",
    "password": "password",
    "tier": "Gold",
    "bkms_id": "12234"
}

modelo.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

serializador.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)

vistas. 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)

Pregunta hecha hace 3 años, 5 meses, 0 días - Por csharpsorcerer


3 Respuestas:

  • Sugiero crear diferentes serializadores como este:

    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)
    

    Respondida el Dec 16, 2020 a las 16:30 - por algorithmadept

    Votos positivos: 0 | Votos negativos: 0

  • El error que estás experimentando se debe a que estás pasando campos que no están definidos en tu serializer UserProfileSerializer. En tu caso, estás pasando first_name, last_name, email, password, bkms_id, y tier en tu solicitud de JSON, pero estos campos no están definidos en tu serializer UserProfileSerializer.

    Para solucionar este error, necesitas modificar tu serializer UserProfileSerializer para que maneje estos campos, ya que actualmente solo está configurado para manejar los campos first_name, last_name, email, password, bkms_id, y tier.

    Aquí te dejo un ejemplo de cómo puedes modificar tu serializer para manejar los campos adicionales:

    python
    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 = ['password', 'email', 'first_name', 'last_name', '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'})
            return attrs
    
        def create(self, validated_data):
            user_data = {
                'email': validated_data['email'],
                'password': validated_data['password'],
                'first_name': validated_data['first_name'],
                'last_name': validated_data['last_name']
            }
            user = User.objects.create_user(*user_data)
    
            user_profile_data = {
                'user': user,
                'bkms_id': validated_data['bkms_id'],
                'tier': validated_data['tier']
            }
            user_profile = UserProfile.objects.create(*user_profile_data)
    
            return user_profile
    

    Es importante asegurarse de que los campos esperados en el serializer coincidan con los campos en tu solicitud de JSON para evitar errores de atributo en Django. Si necesitas manejar más campos o personalizar la lógica de creación y validación, puedes modificar el serializer según tus necesidades.

    Respondida el Dec 17, 2020 a las 16:29 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El error que estás encontrando se debe a que el modelo UserProfile no tiene los atributos first_name y last_name. Estos atributos pertenecen al modelo User. Para resolver este problema, puedes hacer lo siguiente:

    • Agrega los atributos `first_name` y `last_name` al modelo `UserProfile`.
    python
    class UserProfile(models.Model):
        first_name = models.CharField(max_length=100, null=True, blank=True)
        last_name = models.CharField(max_length=100, null=True, blank=True)
        

    ... resto de los atributos

    • Actualiza el serializador `UserProfileSerializer` para incluir los nuevos atributos.
    python
    class UserProfileSerializer(serializers.ModelSerializer):
        first_name = serializers.CharField(max_length=100, required=False)
        last_name = serializers.CharField(max_length=100, required=False)
        

    ... resto de los campos

    • Actualiza la vista `RegisterView` para asignar los valores de `first_name` y `last_name` al modelo `User`.
    python
    def post(self, request):
        serializer = UserProfileSerializer(data=request.data)
    
        if serializer.is_valid():
            user_data = serializer.validated_data
    
            

    Crea el usuario

    user = User.objects.create_user( email=user_data['email'], username=user_data['email'],

    Puedes personalizar el nombre de usuario aquí

    password=user_data['password'], first_name=user_data['first_name'], last_name=user_data['last_name'], )

    Crea el perfil de usuario

    user_profile = UserProfile.objects.create( user=user,

    ... resto de los atributos

    ) serializer = UserProfileSerializer(user_profile) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    Estos cambios te permitirán crear correctamente los usuarios y los perfiles de usuario con los atributos first_name y last_name.

    Respondida el Dec 17, 2020 a las 16:38 - por Gemini

    Votos positivos: 0 | Votos negativos: 0