Django - KeyError: 'profile' - Попытка сохранить профиль пользователя с помощью DRF и Ajax - PullRequest
0 голосов
/ 29 сентября 2019

Я пытаюсь сохранить данные профиля пользователя с помощью DRF и Ajax, но у меня возникает ошибка KeyError.

Я читал документы DRF, особенно эту часть: Доступные для записи вложенные представления это то, что я хочу, но не работает для меня.

Я надеюсь, что вы можете помочь мне

это мой serializer.py

class ProfileSerializer(serializers.ModelSerializer):

    class Meta:
        model = Profile
        fields = ('user', 'avatar', 'dob', 'headline',
                'country', 'location', 'cp', 'background',
                'facebook', 'twitter', 'github', 'website',)
        read_only_fields = ('user', ) # I tried removing this part but, not work (In some forums say it)


class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        exclude = ('password', 'is_superuser', 'is_staff', 'is_active', 'user_permissions', 'groups', 'last_login',)
        read_only_fields = ('username', 'email', 'date_joined', )

    def update(self, instance, validated_data):
        profile_data = validated_data.pop('profile')
        profile = instance.profile

        instance.username = validated_data.get('username', instance.username)
        instance.first_name = validated_data.get('first_name', instance.first_name)
        instance.last_name = validated_data.get('last_name', instance.last_name)
        instance.save()

        profile.avatar = profile_data.get('avatar', profile.avatar)
        profile.dob = profile_data.get('dob', profile.dob)
        profile.headline = profile_data.get('headline', profile.headline)
        profile.country = profile_data.get('country', profile.country)
        profile.location = profile_data.get('location', profile.location)
        profile.cp = profile_data.get('cp', profile.cp)
        profile.background = profile_data.get('background', profile.background)
        profile.facebook = profile_data.get('facebook', profile.facebook)
        profile.twitter = profile_data.get('twitter', profile.twitter)
        profile.github = profile_data.get('github', profile.github)
        profile.website = profile_data.get('website', profile.website)

        profile.save()

        return instance

мой views.py

class ProfileRetrieveAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAuthenticatedOrReadOnly, IsAuthenticatedOrReadOnly, )
    lookup_field = 'username'

    def retrieve(self, request, *args, **kwargs):
        super(ProfileRetrieveAPIView, self).retrieve(request, args, kwargs)
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        data = serializer.data
        response = {
            "message": "Successfully retrieved",
            "data": data,
            "status_code": status.HTTP_200_OK
        }
        return Response(response)

    def patch(self, request, *args, **kwargs):
        super(ProfileRetrieveAPIView, self).patch(request, args, kwargs)
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        data = serializer.data
        response = {
            "message": "Perfil actualizado con éxito",
            "data": data,
            "status": status.HTTP_200_OK
        }
        return Response(response, status=status.HTTP_200_OK)

и мой ajax.js

$("#saveProfile").click(function(e) {
    e.preventDefault();

    var profileData = {
      'avatar': $("#avatar").val(),
      'first_name': $("#first_name").val(),
      'last_name': $("#last_name").val(),
      'country': $("#country").val(),
      'location': $("#location").val(),
      'cp': $("#postal_code").val(),
      'headline': $("#headline").val(),
      'dob': $("#dob").val(),
      'facebook': $("#facebook").val(),
      'twitter': $("#twitter").val(),
      'github': $("#github").val(),
      'website': $("#website").val(),
    }
    $.ajax({
      type: 'PATCH',
      url: "{% url 'profiles:api_profile' username=request.user.username %}",
      data: JSON.stringify(profileData),
      contentType: 'application/json; charset=utf-8',
      success: function(res) {
        console.log(res.data);
      },
      error: function(res) {
        console.log(res);
      }
    });
  });

**** Обновление, я добавил models.py **

class Profile(TimeStampedModel):

    user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name="profile", on_delete=models.CASCADE)
    avatar = ThumbnailerImageField(upload_to=user_directory_path, blank=True, validators=[validate_image_extension])
    dob = models.DateField(_("Date of Birth"), blank=True, null=True)
    headline = models.CharField(_("Headline"), max_length=255)
    country = models.CharField(_("Country"), max_length=100, blank=True)
    location = models.CharField(_("Location"), max_length=255, blank=True)
    cp = models.CharField(_("Postal Code"), max_length=5, blank=True)
    #sector = models.TextField(_("Sector"))
    background = ThumbnailerImageField(upload_to='photos/', blank=True, validators=[validate_image_extension])
    #contact information
    facebook = models.URLField(_("Facebook"), max_length=200, blank=True, null=True)
    twitter = models.URLField(_("Twitter"), max_length=200, blank=True, null=True)
    github = models.URLField(_("GitHub"), max_length=200, blank=True, null=True)
    website = models.URLField(_("Website"), max_length=200, blank=True, null=True)
    enterprise = models.BooleanField(_("Is enterprise account?"), default=False)


    def __str__(self):
        return self.user.get_full_name()

и другие models.py

class TimeStampedModel(models.Model):
    """
    Un modelo base abstracto que provee de campos predeterminados
    para que no sean repetitivos, se puede heredar de este modelo
    a todos los demás para excluir la repeticion de los campos
    ``created_at`` and ``updated_at``.
    """
    created_at = models.DateTimeField(_("Created Date"), auto_now_add=True)
    updated_at = models.DateTimeField(_("Updated Date"), auto_now=True)

    class Meta:
        abstract = True

class User(AbstractUser):

    role = models.BooleanField(_("Enterprise Account"), default=False)

Когда я нажимаю кнопку сохранения, сервер светитмне эта ошибка:

  File "C:\Users\a_niu\.virtualenvs\Vinculacion-S2cHiiVR\lib\site-packages\rest_framework\generics.py", line 288, in patch
    return self.partial_update(request, *args, **kwargs)
  File "C:\Users\a_niu\.virtualenvs\Vinculacion-S2cHiiVR\lib\site-packages\rest_framework\mixins.py", line 82, in partial_update
    return self.update(request, *args, **kwargs)
  File "C:\Users\a_niu\.virtualenvs\Vinculacion-S2cHiiVR\lib\site-packages\rest_framework\mixins.py", line 68, in update
    self.perform_update(serializer)
  File "C:\Users\a_niu\.virtualenvs\Vinculacion-S2cHiiVR\lib\site-packages\rest_framework\mixins.py", line 78, in perform_update
    serializer.save()
  File "C:\Users\a_niu\.virtualenvs\Vinculacion-S2cHiiVR\lib\site-packages\rest_framework\serializers.py", line 208, in save
    self.instance = self.update(self.instance, validated_data)
  File "C:\Users\a_niu\Desktop\practicas\Django\Vinculacion\app\profiles\serializers.py", line 24, in update
    profile_data = validated_data.pop('profile')
KeyError: 'profile'

1 Ответ

0 голосов
/ 29 сентября 2019

Еще раз посмотрите на пример , который вы дали:

class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ['username', 'email', 'profile']

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = User.objects.create(**validated_data)
        Profile.objects.create(user=user, **profile_data)
        return user

Это отличается от вашего кода, потому что profile включен как поле в meta.fields, в то время какпохоже, что вы включили поле profile в свой код.Я думаю, что вы путаете это с атрибутом profile вашего UserSerializer класса, который отличается от вложенного profile объекта вашей User модели.

...