【问题标题】:Django - KeyError: 'profile' - Trying to save the user profile with DRF and AjaxDjango - KeyError: 'profile' - 尝试使用 DRF 和 Ajax 保存用户配置文件
【发布时间】:2020-01-28 18:33:35
【问题描述】:

我正在尝试使用 DRF 和 Ajax 保存用户配置文件数据,但出现错误 KeyError。

我正在阅读 DRF 文档,特别是这部分:Writable Nested Representations 这是我想要的,但对我不起作用。

希望你能帮到我

这是我的 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'

【问题讨论】:

  • 您能否在更新的最开始添加print(validated_data),并向我们展示结果?
  • @CalebGoodman 仅返回 User 模型数据、名字和姓氏,仅此而已。
  • 我添加了一个答案。如果它不能解决你的问题,你能告诉我你的UserProfile 模型吗?

标签: django ajax django-rest-framework


【解决方案1】:

再看看你给的example

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 字段。我认为您将其与UserSerializer 类的profile 属性 混淆了,这与User 模型的嵌套profile 对象不同。 p>

【讨论】:

  • 如果我在profile_data = validated_data.pop('profile') 中添加{} = profile_data = validated_data.pop('profile', {})。错误消失,一切正常,但只保存User数据first_name and last_name,其余数据不保存。
  • @MiguelToledano 您能否添加一个更新以显示您的Profile 模型,以及您的User 模型(如果您继承了默认模型)。
  • 好的,现在检查一下,我用模型更新了这个,我看到,当我通过 AJAX 发送数据时,用户模型数据一切正常,但我认为我的配置文件数据不行错误在update 序列化程序中。
猜你喜欢
  • 2012-08-01
  • 1970-01-01
  • 2021-03-14
  • 2020-09-03
  • 1970-01-01
  • 2017-10-23
  • 1970-01-01
  • 1970-01-01
  • 2021-07-05
相关资源
最近更新 更多