【问题标题】:How to Pass an Image File to a API Endpoint如何将图像文件传递到 API 端点
【发布时间】:2019-11-23 08:41:12
【问题描述】:

我有一个带有 DRF 的 Web 服务,我让 POSTMAN 成功传递了正确的所有字段,包括图像文件 ['avatar'] []1

现在我如何从 Django 表单传递图像文件,但我不断收到错误 400,错误请求。请问我如何编码要传递到 API 端点的图像文件。

html

<form method="post" action="#" enctype="multipart/form-data">
                          {% csrf_token %}
                              <label for="phone">Enter Phone</label>
                              {{ form.phone }} <br />
                              <label for="bvn">Enter BVN</label>
                              {{ form.bvn }} <br />
                              <label for="avatar">Upload Avatar</label>
                              {{ form.avatar }} <br />
                              <button type="submit" class="btn btn-primary" >Submit</button>

                          </form>

views.py

def form_valid(self, form):
    token = self.request.session['session_token']
    headers = {"Content-Type": 'application/json', "Authorization": "Token " + token}

    parameters = {
        'bvn': form.cleaned_data['bvn'],
        'phone': form.cleaned_data['phone'],
        'avatar': self.request.FILES['avatar']
    }
    response = requests.put(str(settings.API_END_POINT + '/customer_profile_api/'), data=parameters,
                             headers=headers)
    if response.status_code in settings.SUCCESS_CODES:
        messages.success(self.request, 'Successfully updated profile')
    else:
        messages.error(self.request, 'API Error %s' % response.status_code)

    return super(CustomerDashboard, self).form_valid(form)

form.py

class ProfileUpdateForm(forms.Form):
    """customer profile update form"""
    phone = forms.CharField(required=False, widget=NumberInput(attrs={'class': 'form-control',
                                                                      'type': 'number', 'id': 'phone',
                                                                      'placeholder': 'Enter Phone Number'}))
    bvn = forms.CharField(required=False, widget=NumberInput(attrs={'class': 'form-control',
                                                                      'type': 'number', 'id': 'bvn',
                                                                      'placeholder': 'Enter BVN'}))
    avatar = forms.ImageField(required=False, widget=ClearableFileInput(attrs={'class': 'form-control',
                                                                      'type': 'file', 'id': 'avatar',
                                                                      'placeholder': 'Upload Avatar'}))

【问题讨论】:

    标签: json django web-services django-rest-framework django-forms


    【解决方案1】:

    你的标题是错误的。

    headers = {"Content-Type": 'application/json', "Authorization": "Token " + token}
    

    改为:

    headers = {"Content-Type": 'multipart/form-data', "Authorization": "Token " + token}
    

    当你上传一些文件时,你应该使用multipart/form-data 而不是application/json (如果您确定不将文件作为 base64 发送)

    【讨论】:

    • 我刚刚更改了标题。现在我正在点击创建/正常状态代码。但是数据不会进入 API...
    • 检查您的代码。你觉得文件在 self.request.FILES['avatar'] 吗?
    • 我实际上打印了 self.request.FILE['avatar'] 的输出,我得到了文件。
    • 我还没有弄清楚如何解决这个问题。有什么帮助吗?
    • 尝试保存文件,然后将他发送到您的 API。
    【解决方案2】:

    如果其他人遇到同样的问题,我能够解决的唯一方法是使用单独的视图来处理图像和其他文本字段。到目前为止我所做的一切都有效。 如果您注意到,处理图像的视图的内容类型标头没有插入,只需将其删除并让您的 API 自行处理,几次我将其设置为 multipart/form-data,我将点击响应代码 200 /201,但文件永远不会被保存。

    我的 API 视图.py

    class CustomerApiView(generics.UpdateAPIView, generics.ListAPIView):
        """Customer Api View to update customer profile"""
        http_method_names = ['put', 'get']
        renderer_classes = [renderers.JSONRenderer]
        authentication_classes = [authentication.TokenAuthentication]
        serializer_class = CustomerSerializer
        queryset = Profile.objects.all()
        permission_classes = [IsAuthenticated]
    
        def get_queryset(self):
            user = self.request.user
            return self.queryset.filter(user=user)
    
        def get_object(self):
            queryset = self.filter_queryset(self.get_queryset())
            # make sure to catch 404's below
            obj = queryset.get(user_id=self.request.user.id)
            self.check_object_permissions(self.request, obj)
            return obj
    
    class CustomerAvatarApiView(generics.UpdateAPIView):
        """Customer Avatar/DP API View"""
        serializer_class = CustomerAvatarSerializer
        queryset = Profile.objects.all()
        authentication_classes = [authentication.TokenAuthentication]
        permission_classes = [IsAuthenticated]
        renderer_classes = [renderers.JSONRenderer]
        http_method_names = ['put', 'get']
    
        def get_object(self):
            queryset = self.filter_queryset(self.get_queryset())
            # make sure to catch 404's below
            obj = queryset.get(user_id=self.request.user.id)
            self.check_object_permissions(self.request, obj)
            return obj
    

    serializer.py

    class CustomerSerializer(serializers.ModelSerializer):
        """Customer Profile Serializer"""
    
        class Meta:
            """Class Meta"""
            model = Profile
            fields = ('pk', 'phone', 'bvn', 'avatar')
            extra_kwargs = {'pk': {'read_only': True}, }
    
    
    class CustomerAvatarSerializer(serializers.ModelSerializer):
        """Separate Serializer to handle upload of file"""
    
        class Meta:
            """Class Meta"""
            model = Profile
            fields = ('avatar', )
    

    我的观点.py

    class CustomerDashboard(LoginRequiredMixin, generic.FormView):
        """customer dashboard view"""
        template_name = 'customer/dashboard.html'
        form_class = ProfileUpdateForm
        raise_exception = False
        success_url = reverse_lazy('customer_dashboard')
    
        def get_profile_api(self):
            """get profile api call to fetch profile; passing in the token from session"""
            token = self.request.session['session_token']
            headers = {"Content-Type": 'application/json', "Authorization": "Token " + token}
            response = requests.get(str(settings.API_END_POINT + '/customer_profile_api/'), headers=headers)
            json_response = response.json()
            return json_response
    
        def get_initial(self):
            initial = ''
            try:
                initial = super(CustomerDashboard, self).get_initial()
                initial['phone'] = self.get_profile_api()[0]['phone']
                initial['bvn'] = self.get_profile_api()[0]['bvn']
            except:
                pass
    
            return initial
    
        def get_context_data(self, **kwargs):
            """overriding get_context_data to pass data to template"""
            context = super(CustomerDashboard, self).get_context_data()
            if self.get_profile_api()[0]['bvn'] != '':  # if BVN has been filled before pass True or False to template
                context['bvn_initial'] = True  # Todo Validate BVN from API Before calling save method on it
            else:
                context['bvn_initial'] = False
    
            return context
    
        def form_valid(self, form):
            token = self.request.session['session_token']
    
            if 'updateAvatar' in self.request.POST:
    
                headers = {"Authorization": "Token " + token}
                avatar = form.cleaned_data['avatar']
    
                file = {'avatar': (str(avatar), avatar)}
    
                response = requests.put(str(settings.API_END_POINT + '/customer_profile_avi_api/'), files=file,
                                        headers=headers)
                message = 'Avatar changes successfully'
    
                if response.status_code in settings.SUCCESS_CODES:
                    messages.success(self.request, message)
                else:
                    messages.error(self.request, 'API Error %s' % response)
    
            elif 'updateProfile' in self.request.POST:
    
                headers = {"Content-Type": "application/json", "Authorization": "Token " + token}
                parameters = {
                    'bvn': form.cleaned_data['bvn'],
                    'phone': form.cleaned_data['phone'],
                }
    
                response = requests.put(str(settings.API_END_POINT + '/customer_profile_api/'), json=parameters,
                                        headers=headers)
                message = 'Profile changes successfully'
    
                if response.status_code in settings.SUCCESS_CODES:
                    messages.success(self.request, message)
                else:
                    messages.error(self.request, 'API Error %s' % response)
    
            return super(CustomerDashboard, self).form_valid(form)
    

    【讨论】:

      猜你喜欢
      • 2021-09-18
      • 1970-01-01
      • 2020-06-24
      • 1970-01-01
      • 2016-10-17
      • 1970-01-01
      • 2021-02-11
      • 2020-01-02
      • 1970-01-01
      相关资源
      最近更新 更多