Python Django REST框架和文件上载(数据URI)

Python Django REST框架和文件上载(数据URI),python,django,django-rest-framework,Python,Django,Django Rest Framework,我想做的是 1) 允许用户选择图像 2) 获取图像并将其添加到画布 3) 允许在CANAV内部进行操作(重新调整大小) 4) 推送“上传” 5) 取下画布并从中生成数据URI 这一切在JS中都非常有效,给我留下了三个隐藏字段: <input type="hidden" id="imageData" name="imageData" /> <input type="hidden" id="imageName" name="imageName" /> <input ty

我想做的是

1) 允许用户选择图像 2) 获取图像并将其添加到画布 3) 允许在CANAV内部进行操作(重新调整大小) 4) 推送“上传” 5) 取下画布并从中生成数据URI

这一切在JS中都非常有效,给我留下了三个隐藏字段:

<input type="hidden" id="imageData" name="imageData" />
<input type="hidden" id="imageName" name="imageName" />
<input type="hidden" id="imageCaption" name="imageCaption" />
我在这里遗漏了一些要点

1) 在哪里/如何截获rest请求以解析/处理传入的rest post,从而能够分离数据URI并将图像存储在磁盘上

2) 我可能一大堆都不明白,所以如果我还遗漏了什么,请告诉我


我认为关键在于重写序列化程序还原字段方法。当它查找基于model.FileField构建的“file”字段时,我需要重定向框架以查找要传递的字段dataUri字段,但我需要实例化一个新字段,对最大长度没有限制。分离dataUri,存储文件,并将文件字段添加到已解析资源的字典中,让框架按计划继续。在这种情况下,不需要重写pre_save,因为需要在验证之前执行此代码

JS:

Python:

class ImageSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Image
        fields = ('file', 'caption','id')

    def saveImage(self, imgFileUri):
        #parse dataUri and save locally, return local path
        return 'somewhereOverTheBlah'

    def restore_fields(self, data, files):
        """
        Core of deserialization, together with `restore_object`.
        Converts a dictionary of data into a dictionary of deserialized fields.
        """
        reverted_data = {}

        if data is not None and not isinstance(data, dict):
            self._errors['non_field_errors'] = ['Invalid data']
            return None

        for field_name, field in self.fields.items():
            print('a: ' + field_name)
            if(field_name == 'file'):
                field_name = 'dataUri'
                field = fields.CharField()
                try:
                    # restore using the built in mechanism
                    field.field_from_native(data, files, field_name, reverted_data)
                    # take the dataUri, save it to disk and return the Path
                    value = reverted_data[field_name]
                    path = self.saveImage(value)
                    # set the file <Path> property on the model, remove the old dataUri
                    reverted_data['file'] = path
                    del reverted_data[field_name]

                except ValidationError as err:
                    self._errors[field_name] = list(err.messages)
            else:
                field.initialize(parent=self, field_name=field_name)
                try:
                    field.field_from_native(data, files, field_name, reverted_data)
                except ValidationError as err:
                    self._errors[field_name] = list(err.messages)

        return reverted_data
类ImageSerializer(serializers.HyperlinkedModelSerializer):
类元:
模型=图像
字段=(‘文件’、‘标题’、‘id’)
def saveImage(self,imgFileUri):
#解析dataUri并本地保存,返回本地路径
返回“somewhere theblah”
def restore_字段(自身、数据、文件):
"""
反序列化的核心,以及“还原对象”。
将数据字典转换为反序列化字段字典。
"""
还原的_数据={}
如果数据不是无且不存在(数据,dict):
self._errors['non_field_errors']=['Invalid data']
一无所获
对于字段名称,self.fields.items()中的字段:
打印('a:'+字段名称)
如果(字段_name=='file'):
字段名称='dataUri'
field=fields.CharField()
尝试:
#使用内置机制进行恢复
field.field_from_native(数据、文件、字段名称、还原的_数据)
#获取dataUri,将其保存到磁盘并返回路径
值=还原的\u数据[字段\u名称]
path=self.saveImage(值)
#设置模型的file属性,删除旧的dataUri
还原的_数据['file']=路径
删除还原的\u数据[字段\u名称]
除ValidationError作为错误外:
self.\u errors[字段\u name]=列表(错误消息)
其他:
初始化(父项=自身,字段名称=字段名称)
尝试:
field.field_from_native(数据、文件、字段名称、还原的_数据)
除ValidationError作为错误外:
self.\u errors[字段\u name]=列表(错误消息)
返回还原的_数据
1) 在何处/如何截获rest请求以解析/处理 传入的REST post能够分离数据URI并存储 磁盘上的图像

我不清楚REST框架如何适应这种情况,但表单提交的数据要么是
[request.POST]
,要么是
[request.FILES]
()。这些对象将在窗体发布到的Django视图中可用。下面是一个简单的例子来说明:

from django.shortcuts import render
from django.http import HttpResponseRedirect

def contact(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ContactForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            # Process the data in form.cleaned_data
            # ...
            return HttpResponseRedirect('/thanks/') # Redirect after POST
    else:
        form = ContactForm() # An unbound form

    return render(request, 'contact.html', {
        'form': form,
    })
2) 我可能一大堆都不明白,所以如果有 还有什么我不知道的,请告诉我


有一件事可能会有帮助,那就是深入研究“”。哦,我刚刚意识到你可能没有使用;如果不是,那将是一个很好的起点(包括ModelForms)。此外,还有一个智能管理文件上传的服务,名为;这是一个非常无缝的集成。如果最终使用Filepicker进行数据和架构迁移,您应该阅读以下内容:

如果您计划继续使用
视图集.ModelViewSet
,那么您可以使用GenericAPIView可用的任何方法重写-在GenericAPIView方法部分中简要介绍并完整记录

对您最有用的可能是框架提供的
pre_save
post_save
挂钩,您可以使用自己的方法覆盖这些挂钩,从而将自己的自定义代码添加到视图中<正如您可能期望的那样,在视图保存发布的数据之前,会调用code>pre_save。其中一个参数是要保存的对象:

def pre_save(self, obj):
因此,此时可以执行数据充实等操作

如果这对您来说不够灵活,那么构建您自己的自定义视图是非常简单的,它为您提供了完整的控制-请查看一个比我能提供的更好的解释

更新-绕过下面评论中提到的验证问题

DRF在调用
pre_save
之前执行验证,因此如果post数据中缺少
文件
字段,则在自定义
pre_save
代码有机会执行之前,您的更新将被拒绝。有两种方法可以解决这个问题:

  • validate_(self、attrs、source)
    方法添加到序列化程序中(
    validate_file()
    )。无论您的post数据中是否填充了字段,都将调用此函数,您可以在此处进行处理,并在返回前将
    文件添加到
    属性中。请注意,如果
    文件
    将基于模型中的其他字段,那么实现模型级验证器(
    验证(self,attrs)
    )可能更合适。有关更多信息,请参阅。

    from django.shortcuts import render from django.http import HttpResponseRedirect def contact(request): if request.method == 'POST': # If the form has been submitted... form = ContactForm(request.POST) # A form bound to the POST data if form.is_valid(): # All validation rules pass # Process the data in form.cleaned_data # ... return HttpResponseRedirect('/thanks/') # Redirect after POST else: form = ContactForm() # An unbound form return render(request, 'contact.html', { 'form': form, })
    def pre_save(self, obj):
    
    class ImageSerializer(serializers.HyperlinkedModelSerializer):
        class Meta:
            model = Image
            fields = ('file', 'caption','id')
    
        def saveImage(self, imgFileUri):
            #parse dataUri and save locally, return local path
            return 'somewhereOverTheBlah'
    
        def restore_fields(self, data, files):
            """
            Core of deserialization, together with `restore_object`.
            Converts a dictionary of data into a dictionary of deserialized fields.
            """
            reverted_data = {}
    
            if data is not None and not isinstance(data, dict):
                self._errors['non_field_errors'] = ['Invalid data']
                return None
    
            for field_name, field in self.fields.items():
                """
                So it  is iterating over the fields to serialize, when we find the file field
                do something different (in this case look for the fileUri field, handle it and replace
                it inside of the reverted_data dictionary with the intended file field
                """
    
                if(field_name == 'file'):
                    field_name = 'dataUri'
                    field = fields.CharField()
                    try:
                        # restore using the built in mechanism
                        field.field_from_native(data, files, field_name, reverted_data)
                        # take the dataUri, save it to disk and return the Path
                        value = reverted_data[field_name]
                        path = self.saveImage(value)
                        # set the file <Path> property on the model, remove the old dataUri
                        reverted_data['file'] = path
                        del reverted_data[field_name]
    
                    except ValidationError as err:
                        self._errors[field_name] = list(err.messages)
                else:
                    field.initialize(parent=self, field_name=field_name)
                    try:
                        field.field_from_native(data, files, field_name, reverted_data)
                    except ValidationError as err:
                        self._errors[field_name] = list(err.messages)
    
            return reverted_data