1

这里隐藏了一些相关的小问题,但它们确实指向一个大而多毛的最佳实践问题。这是一个很难实现的功能,因为它应该一次做一些棘手的事情......

  • 拖放式多文件上传器(通过 Javascript)
  • 多页表单(第一页:上传文件并将文件与现有文档模型关联;第二页:更新和保存文件/文档对象和元数据到数据库)

...而且我还没有在任何地方找到预先存在的代码示例或实现。(根据一个人的方法,它可以扫除桌面或自动回答所有相关/嵌入式/后续问题。)底线,这篇文章的目的是回答这个问题:什么是最优雅的方法,可以最大限度地减少介入问题/问题?

我在 Django 中使用这个拖放式 JQuery 文件上传器的实现来上传文件......

https://github.com/miki725/Django-jQuery-File-Uploader-Integration-demo

当然,我上面链接的解决方案将文件保存在文件系统上,但是在每个上传会话中分批保存,通过为每批文件创建一个目录,然后为每个目录分配一个 UUID。文件系统上每个唯一命名的目录都包含在该特定上传会话期间上传的文件。这意味着任何类型的数据库存储方法都必须首先梳理并迭代此解决方案为每个上传会话创建的文件系统目录中的所有文件。

注意:上面链接的 JQuery 解决方案不使用 app 目录中的表单(在 forms.py 中)。表单被硬编码到模板中,这已经有点令人沮丧了......因为现在我还必须找到一种很好的方法来将每批中的每个上述文件绑定到一个表单。

认为最简单的——尽管可能是性能最差的解决方案——是为两个表单创建两个视图……将每个文件保存到第一页视图中的数据库中,然后在第二页上更新数据库。这是我目前正在滚动的方向:

在模板中...

...uploader javascripts in header...

<form action="{% url my_upload_handler %}" method="POST" enctype="multipart/form-data">
    <input type="file" name="files[]" multiple
</form>

在 VIEWS.PY...

def my_upload_handler_0r_form_part_one(request):

# POST(在上传处理程序中;由上传操作触发的请求)

    if request.method == 'POST':
        if not ("f" in request.GET.keys()):

          ...validators and exception handling...
          ...response_data, which is a dict...

            uid = request.POST[u"uid"]

            file = request.FILES[u'files[]']
            filename = os.path.join(temp_path, str(uuid.uuid4()) + file.name)
            destination = open(filename, "wb+")
            for chunk in file.chunks():
                destination.write(chunk)
            destination.close()

            response_data = simplejson.dumps([response_data])
            response_type = "application/json"
            # return the data to the JQuery uploader plugin...
            return HttpResponse(response_data, mimetype=response_type)

# GET(在同一个上传处理程序中)

    else:    
            return render_to_response('my_first_page_template.html',
                              {                     <---NO 'form':form HERE
                              'uid': uuid.uuid4(),
                              },
                              context_instance = RequestContext(request))


def form_part_two(request):

    #here I need to retrieve and update stuff uploaded on first page

    return render_to_response('my_second_page_template.html', 
    {}, 
    context_instance = RequestContext(request))

第一个页面的这个视图利用了 JQuery 上传器,它非常适合每个会话的多文件上传,并且可以完成它应该做的事情。然而,正如上面所暗示的,作为上传处理程序的视图只是需要成为两页表单的第一页。在第二页,最终用户随后需要检索每个上传的文件,将附加数据附加到他们刚刚在第一页上传的文件,然后重新保存到数据库中。

我试图通过各种解决方案将这项工作作为两部分表单工作,包括表单向导和/或基于通用类的视图......以下示例主要通过会话实现数据持久性。这些解决方案很快就会变得相当棘手。

总之,我需要...

  • 以唯一标识的批次上传多个文件(通过拖放)
  • 梳理并迭代每批上传的文件
  • 将批处理中的每个文件绑定到一个表单并将其与现有文档模型相关联
  • 一次提交/保存所有这些文件到数据库
  • 在潜在新表单的下一页/模板上检索这些文件中的每一个
  • 更新每个文件的元数据
  • 一次重新提交/保存所有这些文件到数据库

所以......您可以通过涉及以下相关问题来了解上述所有内容如何增加简单文件上传的复杂性,并增加提供该功能的复杂性:

forms.py:如何最好地将每个文件绑定到一个表单

models.py:如何将每个文件与预先存在的文档模型相关联

views.py如何按照 Postgres 中预先存在的文档模型在第一页保存每个文件;更新并保存第二页中的每个文档

...而且,我想在没有表单向导和基于类的视图的情况下完成所有这些工作。(尤其是对于这个用例,CBV 让我有点难以理解。)换句话说:我正在寻找可能导致最防弹且易于阅读/理解的解决方案的建议。如果它导致对数据库的多次点击,那对我来说很好。(如果将文件保存到数据库似乎是反最佳做法,请参阅另一篇文章:Storing file content in DB

我是否可以为两个表单创建一个单独的视图,并将标准上传表单子类化,就像这样......

在forms.py...

class FileUploadForm(forms.Form):

    files = forms.FileField(widget=forms.ClearableFileInput(attrs={'name':'files[]', 'multiple':'multiple'}))
    #how to iterate over files in list or batch of files here...?
        file = forms.FileField()

    file = forms.FileField()

    def clean_file(self):
        data = self.cleaned_data["file"]

        # read, parse, and create `data_dict` from file...
        # subclass pre-existing UploadModelForm      
        **form = UploadModelForm(data_dict)**

        if form.is_valid():
            self.instance = form.save(commit=False) 
        else:
            raise forms.ValidationError
        return data

...然后重构上面的早期上传处理程序,例如...

在views.py 中,将以下内容替换为当前的上传处理程序...

    def view_for_form_one(request):  
        ...
        # the aforementioned upload handler logic, plus...
        ...
        form = FileUploadForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
        else:
            # display errors
            pass
        ...

    def view_for_form_two(request):

        # update and commit all data here

...?

4

1 回答 1

3

一般来说,对于这种类型的问题,我喜欢创建带有一个页面的单个页面<form>,但用户使用 javascript 浏览多个部分。

使用 javascript 将表单分解为多部分的向导式表单系列要容易得多,尤其是如果它产生的数据本质上是动态的。

如果您绝对必须将其分成多个页面,我建议您设置您的应用程序,以便能够在每个步骤结束时将数据保存到数据库中。

您可以通过使用户在步骤 2 中添加的元数据成为可为空的字段,甚至将元数据移动到单独的模型来实现这一点。

于 2013-05-30T13:49:04.073 回答