更新个人资料头像 DRF 和 Vue.js

Update profile avatar DRF and Vue.js

我不完全理解为什么我不能在我的 DRF api 中更新图像 url。我将 djoser 用于 api 端点和激活,django rest 框架和 vue.js 用于前端,axios 发出 API 请求。我相信(我可能错了!)我无法使用 FormData() 向 Axios 发出补丁请求,因此通过谷歌搜索我找到了另一种方法,但我仍然收到 HTTP 500 错误和 Django 错误:

Internal Server Error: /api/v1/users/me/
Traceback (most recent call last):
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/djoser/views.py", line 175, in me
    return self.partial_update(request, *args, **kwargs)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/rest_framework/mixins.py", line 82, in partial_update
    return self.update(request, *args, **kwargs)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/rest_framework/mixins.py", line 68, in update
    self.perform_update(serializer)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/djoser/views.py", line 149, in perform_update
    super().perform_update(serializer)
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/rest_framework/mixins.py", line 78, in perform_update
    serializer.save()
  File "/Users/markmckeon/Django_Stuff/Relate/environment_3_8_8/lib/python3.8/site-packages/rest_framework/serializers.py", line 208, in save
    assert self.instance is not None, (
AssertionError: `update()` did not return an object instance.

我不确定这是图像文件处理方式的后端问题还是前端提交文件的方式?

这是我的 serializers.py:

class ProfileSerializer(serializers.ModelSerializer):

    user = serializers.StringRelatedField(read_only=True)

    class Meta:
        model = Profile       
        fields = ("__all__")

class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer(required=False, allow_null=True)
    
    class Meta:
        model = User
        fields = ['username', 'profile', 'password']
        extra_kwargs = {"password":{'write_only': True}}

    

    def update(self, instance, validated_data):
        parser_classes = (MultiPartParser)
        if 'profile' in validated_data:
            nested_serializer = self.fields['profile']
            nested_instance = instance.profile
            nested_data = validated_data.pop('profile')

            nested_serializer.update(nested_instance, nested_data)


            return super(UserSerializer, self).update(instance, validated_data) 

    def create(self, validated_data):
        return User.objects.create_user(**validated_data)

如您所见,我正在更新嵌套的用户模型以将用户个人资料和用户详细信息放在一起。

Vue.js:

methods: {

     updateAvatar() {

          const token = localStorage.getItem('token')
          const image = this.fileName
          const formData = new FormData();
                    const data = {
                    profile: {
                        avatar: image,
                        },
                    username: this.user_profile[0]["username"],
                    password: token
                  };
          console.log("Pre send: ", data);

          for(let dataKey in data) {
            if(dataKey === 'avatar') {
              // append nested object
              for (let previewKey in data[dataKey]) {
                formData.append(`avatar[${previewKey}]`, data[dataKey][previewKey]);
              }
            }
            else {
              formData.append(dataKey, data[dataKey]);
            }
          }

          const base = {
                    baseURL: 'http://127.0.0.1:8000',
                    headers: {
                            "Content-Type": "multipart/form-data"
                    },
                    xhrFields: {
                      withCredentials: true
                    }
                  };
          const axiosInstance = axios.create(base);
                      axiosInstance({
                        url: "/api/v1/users/me/",
                        data: formData,
                        method: "patch"
                      })
          // axios

          //   .patch(`/api/v1/users/me/`, formData)
            
            .then((response) => {
              const newArray = response.data;
              console.log("Userchanges: ", newArray);
            })

            .catch((error) => console.log(error.response));
    }
  },

最后是我的 DRF 用户实例:

尝试取消缩进 update 方法中的 super 调用:

def update(self, instance, validated_data):
    parser_classes = (MultiPartParser)
    if 'profile' in validated_data:
        ...

    # unindented
    return super(UserSerializer, self).update(instance, validated_data)

编辑:

ProfileSerializer 应该可以正常工作,尽管我不确定 nested_serializer = self.fields['profile'] 并通过显式 .update() 更新相关实例。尝试将您的代码重写为如下内容:

if 'profile' in validated_data:
    nested_instance = instance.profile
    nested_data = validated_data.pop('profile')
    Profile.objects.filter(pk=nested_instance.pk).update(**nested_data)

如果问题仍然存在,请重新检查来自前端的请求负载。