Django-Tastypie中的Multipart / Form-Data POST,PUT,PATCH

时间:2014-08-07 12:08:14

标签: python django tastypie

我需要在django中使用tastypie修补用户个人资料图片。我使用Django 1.6,AngularJs,它使用Django的普通Authentication()和DjangoAuthorization()类。

当我尝试使用'CONTENT-TYPE:Multipart / form-data'上传图像时。我收到以下错误。

error_message: "You cannot access body after reading from request's data stream"

首先,我知道Tastypie对多部分表单数据没有官方支持。我希望有一个猴子补丁或任何有效的东西,直到tastypie支持多部分数据。

我已对上述内容进行了一些研究,并调查了一些问题:

参考文献:

  1. Django-Tastypie Deserializing Multipart Form Data
  2. Accessing Post Data inside Tastypie
  3. 虽然上面的方法看起来像是一个黑客......我想在我的资源中尝试一下。

    我的资源如下:

    
    class UserProfileResource(ModelResource):
        user = fields.ToOneField(UserResource, 'user', full=True)
        profile_img = fields.FileField(attribute="img", null=True, blank=True)
    
        """docstring for ProfileResource"""
        def alter_list_data_to_serialize(self, request, data):
            if request.GET.get('meta_only'):
                return {'meta': data['meta']}
            return data
    
        def authorized_read_list(self, object_list, bundle):
            return object_list.filter(user=bundle.request.user).select_related()
    
        def obj_create(self, bundle, **kwargs):
            return super(UserProfileResource, self).obj_create(bundle, user=bundle.request.user)
    
        def dehydrate(self, bundle):
            bundle.data['groups'] = [g.name for g in bundle.request.user.groups.all()]
            return bundle
    
        """Deserialize for multipart Data"""
        def deserialize(self, request, data, format=None):
            if format is None:
                format = request.META.get('CONTENT_TYPE','application/json')
            if format == 'application/x-www-form-urlencoded':
                return request.POST
            elif format.startswith('multipart'):
                data = request.POST.copy()
                data.update(request.FILES)
                return data
            return super(UserProfileResource, self).deserialize(request, data, format)
    
        """PATCH For Making the request._body = FALSE"""
        def put_detail(self, request, **kwargs):
            if request.META.get('CONTENT_TYPE').startswith('multipart') and \
                    not hasattr(request, '_body'):
                request._body = ''
    
            return super(UserProfileResource, self).put_detail(request, **kwargs)
    
        """PATCH for MAKING the request._body = FALSE"""
        def convert_post_to_VERB(request, verb):
            """
            Force Django to process the VERB. Monkey Patch for Multipart Data
            """
            if request.method == verb:
                if hasattr(request, '_post'):
                    del (request._post)
                    del (request._files)
    
                request._body  # now request._body is set
                request._read_started = False  # so it won't cause side effects
                try:
                    request.method = "POST"
                    request._load_post_and_files()
                    request.method = verb
                except AttributeError:
                    request.META['REQUEST_METHOD'] = 'POST'
                    request._load_post_and_files()
                    request.META['REQUEST_METHOD'] = verb
                setattr(request, verb, request.POST)
            return request
    
        class Meta:
            queryset = UserProfile.objects.filter()
            resource_name = 'user_profile'
            list_allowed_methods = ['get', 'post']
            detail_allowed_methods = ['get', 'post', 'put', 'delete', 'patch']
            serializer = Serializer()
            authentication = Authentication()
            authorization = DjangoAuthorization()
            always_return_data = True
    
    

    上面提到的参考文献说明 convert_post_to_VERB()方法不是为了处理Multipart数据,而是修补 request._read_started = False 。我们将能够使用tastypie上传文件。但是出于某种原因,即使在我完成上述补丁之后,我仍然会收到相同的“错误:从请求的数据流中读取后无法访问正文”。

    请帮助我解决问题,我错过了什么?或者是否有人有一个工作逻辑,以便我可以举个例子。

    更新:

    • 在我的资源中修补了 put_detail()方法之后放入Works。
    • 我为 update_detail()做了同样的事情,以便让PATCH正常工作,但无论如何都没有用..

1 个答案:

答案 0 :(得分:4)

您需要定义patch_detail而不是update_detail

这就是我的MultipartResource的样子:

class MultipartResource(object):

    def deserialize(self, request, data, format=None):

        if not format:
            format = request.META.get('CONTENT_TYPE', 'application/json')

        if format == 'application/x-www-form-urlencoded':
            return request.POST

        if format.startswith('multipart/form-data'):
            multipart_data = request.POST.copy()
            multipart_data.update(request.FILES)
            return multipart_data

        return super(MultipartResource, self).deserialize(request, data, format)

    def put_detail(self, request, **kwargs):
        if request.META.get('CONTENT_TYPE', '').startswith('multipart/form-data') and not hasattr(request, '_body'):
            request._body = ''
        return super(MultipartResource, self).put_detail(request, **kwargs)

    def patch_detail(self, request, **kwargs):
        if request.META.get('CONTENT_TYPE', '').startswith('multipart/form-data') and not hasattr(request, '_body'):
            request._body = ''
        return super(MultipartResource, self).patch_detail(request, **kwargs)

我在我的资源上使用ModelResource进行多重继承:

class MyResource(MultipartResource, ModelResource):
    pass

顺便说一句,为您的资源设置convert_post_to_VERB方法是没有意义的。不幸的是,在tastypie的Resource类中,这不是一种可以覆盖的方法。他们将其定义为resource.py模块中的一个函数。