1

Pardon me, I'm developing an app using Django REST Framework and when I try to update an user this happen

It throw me this error:

centros = validated_data.pop('centros')

KeyError: 'centros'

I'll share my code:

This is my model

class Usuario(AbstractBaseUser):
    organizacion = models.CharField(verbose_name='Organización', blank=True, null=True, max_length=250)
    departamento = models.CharField(verbose_name='Departamento', blank=True, null=True, max_length=250)
    centros = models.ManyToManyField(Centro, verbose_name='Centro o Unidad', blank=True, related_name='centros_usuario')
    telefono = models.CharField(max_length=100, verbose_name='Teléfono', blank=True, null=True)
    rut = models.CharField(max_length=100, verbose_name='RUT', blank=True, null=True)
    profesion = models.CharField(max_length=150, verbose_name='Profesión', blank=True, null=True)
    cargo = models.CharField(max_length=150, verbose_name='Cargo', blank=True, null=True)
    nacionalidad = models.CharField(max_length=100, verbose_name='Nacionalidad', blank=True, null=True)
    sexo = models.CharField(max_length=10, choices=SEXO_CHOICES ,verbose_name='Sexo', blank=True, null=True)
    fecha_nacimiento = models.DateField(auto_now=False, auto_now_add=False,verbose_name='Fecha de nacimiento', blank=True, null=True)
    imagen_perfil = models.ImageField(upload_to='perfil/', verbose_name='Imágen de Perfil', max_length=255, blank=True, null=True)
    cv = models.FileField(verbose_name='CV', upload_to='cv_usuarios/', blank=True, null=True)
    direccion = models.CharField(max_length=250, blank=True, null=True, verbose_name='Dirección')
    perfil = models.PositiveSmallIntegerField(
        null=False,
        blank=False,
        default=2,
        choices=PERFIL_CHOICES,
        verbose_name='Perfil')
    is_active = models.BooleanField(
        verbose_name='active',
        default=True,
        help_text=(
            'Designates whether this user shoud be treated as active. '
            'Unselect this instead of deleting accounts. '
        )
    )
    estado = models.CharField(verbose_name='Estado usuario', default='INHABILITADO', choices=ESTADO_CHOICES, max_length=13)
    is_staff = models.BooleanField(
        verbose_name='staff status',
        default=False,
        help_text=(
            'Designates whether the user can log into this admin site. '
        )
    )
    is_superuser = models.BooleanField(
        verbose_name='superuser status',
        default=False,
        help_text=(
            'Designates whether this user is a Superuser. '
        )
    )
    terminos_y_condiciones = models.BooleanField(verbose_name='Términos y Condiciones', default=False)
    linkedin = models.CharField(verbose_name='Linkedin', max_length=100, blank=True, null=True)
    email = models.EmailField(max_length=250, unique=True, verbose_name='Correo')
    first_name = models.CharField(max_length=250, verbose_name='Nombre')
    last_name = models.CharField(max_length=250, verbose_name='Apellido', blank=True, null=True)



    objects = UsuarioManager()

    USERNAME_FIELD = 'email'

    def __str__(self):
        return self.first_name
    
    def get_email_user(self):
        return self.email.lower()
    
    def save(self, *args, **kwargs):
        self.email = self.email.lower()
        return super(Usuario, self).save(*args, **kwargs)

This is the serializer class that I'm using to update the users:

class UpdateUsuarioSerializer(serializers.ModelSerializer):
    email = serializers.CharField(max_length=250, required=False)
    first_name = serializers.CharField(max_length=250, required=False)
    class Meta:
        model = Usuario
        fields = ['organizacion',
                  'departamento',
                  'centros',
                  'telefono',
                  'rut',
                  'profesion',
                  'cargo',
                  'nacionalidad',
                  'sexo',
                  'fecha_nacimiento',
                  'imagen_perfil',
                  'cv',
                  'email',
                  'first_name',
                  'last_name',
                  'linkedin'
                  ]
    
    def update(self, instance, validated_data):
        with transaction.atomic():
            centros = validated_data.pop('centros')
            instance = super(UpdateUsuarioSerializer, self).update(instance,validated_data)
            instance.save()
            instance.centros.clear()

            
            for centro in centros:
                instance.centros.add(Centro.objects.get(id=centro))
            
                    
            return instance

And this is the viewset:

class UsuarioViewSet(viewsets.ModelViewSet):
    queryset = Usuario.objects.filter(is_active = True)
    permission_classes = [permissions.AllowAny]
    serializer_class = UsuarioSerializer
    pagination_class = StandardResultsSetPagination
    filter_backends = [DjangoFilterBackend, filters.SearchFilter]
    filterset_fields = ['perfil']
    search_fields = ['first_name', 'last_name', 'email', 'rut', 'telefono', 'profesion', 'cargo', 'centros__nombre']

    def create(self, request):
        imagen_perfil = request.data.get('imagen_perfil', None) or None
        if imagen_perfil is not None:
            try:
                request.data['imagen_perfil'] = file64bits(imagen_perfil)
            except ValueError as error:
                raise serializers.ValidationError({'imagen_perfil': 'Error en formato de archivo'})
        cv = request.data.get('cv', None) or None
        if cv is not None:
            try:
                request.data['cv'] = file64bits(cv)
            except ValueError as error:
                raise serializers.ValidationError({'cv': 'Error en formato de archivo'})
        serializer = UsuarioSerializer(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)

    def update(self, request, pk=None):
        imagen_perfil = request.data.get('imagen_perfil', None) or None
        if imagen_perfil is not None:
            try:
                request.data['imagen_perfil'] = file64bits(imagen_perfil)
            except ValueError as error:
                raise serializers.ValidationError({'imagen_perfil': 'Error en formato de archivo'})
        cv = request.data.get('cv', None) or None
        if cv is not None:
            try:
                request.data['cv'] = file64bits(cv)
            except ValueError as error:
                raise serializers.ValidationError({'cv': 'Error en formato de archivo'})

        instance = Usuario.objects.get(id=pk)
        serializer = UpdateUsuarioSerializer(instance, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

If anyone know how to solve this problem, I'll be so thankful

I was searching many python and django forums but any answer could solve my problem

1 Answers1

0

try this in serializers.py:

def update(self, instance, validated_data):
    centros = validated_data.pop('centros', False)
    if centros:
       with transaction.atomic():
            instance = super(UpdateUsuarioSerializer, self).update(instance,validated_data)
            instance.save()
            instance.centros.clear()

            
            for centro in centros:
                instance.centros.add(Centro.objects.get(id=centro))
            
                    
            return instance