【问题标题】:How to upload an image through copy / paste using django modelform?如何使用 django modelform 通过复制/粘贴上传图像?
【发布时间】:2017-09-14 20:50:56
【问题描述】:

我是 django 的新手,正在尝试将 google apps script (GAS) webapp 迁移到 django。

我在 google 网站上的一个功能是从剪贴板捕获粘贴的图像并通过表单提交。这是通过表单中的隐藏字段完成的:

<input type="hidden" name="summaryImage" id='summaryImage' value=''>

然后我捕获粘贴事件来填充这个隐藏的表单域

/* Handle paste events */
function pasteHandler(e) {
   if (e.clipboardData) {
      // Get the items from the clipboard
      var items = e.clipboardData.items;
      if (items) {
         // Loop through all items, looking for any kind of image
         for (var i = 0; i < items.length; i++) {
            if (items[i].type.indexOf("image") !== -1) {
               // We need to represent the image as a file,
               var blob = items[i].getAsFile();
               var URLObj = window.URL || window.webkitURL;
               var source = URLObj.createObjectURL(blob);
               var reader = new FileReader();
               reader.onload = function(e) {
                 document.getElementById("summaryImage").value= reader.result;
               }
               reader.readAsDataURL(blob);
            } 
          }
      }
   } 
}

上述表单通过google提交时,可以在服务器端google应用脚本(GAS)从表单中的summaryImage字段解析,如下所示:

var splitBase = form.summaryImage.split(','),
var type = splitBase[0].split(';')[0].replace('data:','');
var byteCharacters = Utilities.base64Decode(splitBase[1]);
var blob = Utilities.newBlob(byteCharacters, type);

现在,在 django 中,我无法复制它。我在 models.py 中创建了一个带有 ImageField 的模型:

...
image = models.ImageField(blank=True, null=True, verbose_name='Image')
...

并在 forms.py 中将小部件设置为 HiddenInput()

class MyForm(forms.ModelForm):

    class Meta:
        model = myModel
        fields = '__all__'
        widgets = {
            'image': forms.HiddenInput()
        }
    ...

甚至在捕获粘贴时,我将其设置为这个隐藏的图像字段:

document.getElementById("id_image").value= reader.result;

但后来我无法提交表单,收到一条错误消息:

(隐藏字段图像)未提交文件。检查编码类型 表格。

我搜索了很多,但找不到任何关于在 django 中从剪贴板捕获粘贴图像的内容。这甚至可行吗?

【问题讨论】:

  • 在 html 中,您的输入类型为 hidden 而不是 image。我猜 Django 表单应该有一个 CharField 来接受粘贴的数据。在表单清理和保存方法中,您将该字符串数据转换为文件对象并使用它来填充 ImageField。
  • @allcaps 谢谢!!它似乎确实有效并将数据捕获为字符串。它看起来像这样: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAWCAYAAAAvg9c4AAAAMUlEQVRIDWP8////fwYqAyYqmwc2btRQ6ofqaJiOhimVQ2A0SVE5QBkYGEbDdIiEKQC6hwQozNWIkwAAAABJRU5ErkJggg==
  • @allcaps,但我想需要一个更大的字段来保存图像并且 CharField maxlength 是不够的。我会试试textarea。有没有更好的方法/字段类型来捕获这些数据?
  • 不,将字符字段添加到表单而不是模型。来自 charfield 上的表单文档:Validates max_length or min_length, if they are provided. Otherwise, all inputs are valid.。所以你不需要 textarea。

标签: django google-apps-script django-forms modelform


【解决方案1】:

感谢@allcaps 的建议,我找到了解决方案。

基本上,我将 ImageField(图像)保留在我的模型中,并分配了一个自定义小部件以仅使用 id id_image 显示它。然后在表单中添加一个隐藏的输入字段image_container来接收粘贴的数据。表单的保存函数被重写以创建文件并将其保存回 ImageField。

class PictureWidget(forms.widgets.Widget):
    def render(self, name, value, attrs=None):
        if str(value) == '':
            html1 = "<img id='id_image' style='display:block' class='rounded float-left d-block'/>"
        else:
            html1 = "<img id='id_image' style='display:block' class='rounded float-left d-block' src='" + settings.MEDIA_URL + str(value) + "'/>"
        return mark_safe(html1)

class MyForm(forms.ModelForm):

    image_container = forms.CharField(required=False, widget=forms.HiddenInput())
    class Meta:
        model = MYMODEL
        fields = '__all__'
        widgets = {
            'image': PictureWidget(),
        }
    def save(self, commit=True):
        # check image_container data
        self.instance.image.delete(False)
        imgdata = self.cleaned_data['image_container'].split(',')
        try:
            ftype = imgdata[0].split(';')[0].split('/')[1]
            fname = slugify(self.instance.title)
            self.instance.image.save('path/%s.%s' % (fname, ftype), ContentFile(imgdata[1].decode("base64")))
        except:
            pass
        return super(MyForm, self).save(commit=commit)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-05
    • 2011-03-16
    • 2018-05-22
    • 2021-09-05
    • 2017-07-09
    • 2020-01-16
    相关资源
    最近更新 更多