You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django表单中正确保存Dropzone文件并从数据库读取?

Django + Dropzone 拖拽上传解决方案

问题描述

我正在Django应用里实现拖拽上传功能,找不到Dropzone与Django结合的实用资料。之前用普通多文件上传功能一切正常,但拖拽上传更便捷,所以打算切换。目前已经把Dropzone集成到主表单中,但完全不清楚该如何保存这些文件,以及后续如何在模板中从数据库读取它们。本人JS经验不足,希望得到帮助。

现有代码

models.py

class Post(models.Model):
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE
    )
    title = models.CharField(
        max_length=200,
    )
    # 其他字段...


class PostImages(models.Model):
    post = models.ForeignKey(
        Post,
        on_delete=models.CASCADE,
        related_name='images',
    )
    file = models.FileField(
        upload_to="posts/images",
        validators=[],
    )

views.py

class PostCreateView(AuthRequiredMixin, SuccessMessageMixin, View):
    template_name = 'create_post.html'
    model = Post
    form = PostCreationForm
    success_url = reverse_lazy('index')
    success_message = _('Post created successfully')

    def get(self, request, *args, **kwargs):
        form = self.form()
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form(request.POST, request.FILES)
        if form.is_valid():
            new_post = form.save(commit=False)
            new_post.author = request.user
            new_post.save()
            # 移除重复的form.save(),因为new_post已保存
            # form.save()
            for img in request.FILES.getlist('images'):
                # 简化文件保存逻辑,直接使用UploadedFile对象
                new_file = PostImages(post=new_post)
                new_file.file.save(img.name, img)
                new_file.save()
            messages.success(request, self.success_message)
        else:
            messages.error(request, 'Something went wrong!')
        return redirect(self.success_url)

forms.py

class PostCreationForm(ModelForm):
    # 注释原文件字段,改用Dropzone处理
    # images = forms.FileField(
    #     label='Images',
    #     required=False,
    #     help_text='Upload your images here!',
    #     widget=forms.ClearableFileInput(attrs={'multiple': True}),
    # )

    class Meta:
        model = Post
        fields = [
            'title',
            # 其他字段...
        ]
        labels = {
            'title': 'Title',
            # 其他字段标签...
        }

create_post.html

<div class="card border-0 rounded shadow mb-5 p-5">
    <h1>Create Post</h1>
    <form id="create-post" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        {% bootstrap_form form %}
        <div id="previewsContainer" class="dropzone">
            <div class="dz-default dz-message">
                <button class="dz-button" type="button">
                    Drop files here to upload
                </button>
            </div>
        </div>
        {% bootstrap_button content="Create"%}
    </form>
</div>

<script>
    Dropzone.autoDiscover = false;
    new Dropzone("#create-post",{
      clickable: ".dropzone",
      url: "{% url 'create_post' request.user.slug %}",
      previewsContainer: "#previewsContainer",
      paramName: "images",
      maxFiles: 10,
      maxFilesize: 10,
      uploadMultiple: true,
      autoProcessQueue: false,
      // 携带CSRF令牌,避免验证失败
      headers: {
        'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
      },
      init() {
        var myDropzone = this;
        // 绑定提交按钮触发放队列上传
        this.element.querySelector("[type=submit]").addEventListener("click", function(e){
          e.preventDefault();
          e.stopPropagation();
          // 无文件时直接提交表单,有文件则处理上传队列
          if (myDropzone.getQueuedFiles().length > 0 || myDropzone.getAcceptedFiles().length > 0) {
            myDropzone.processQueue();
          } else {
            this.form.submit();
          }
        });
        // 上传完成后自动跳转
        myDropzone.on("queuecomplete", function() {
          window.location.href = "{% url 'index' %}";
        });
      }
    });
</script>

关键调整说明

  1. 后端文件保存优化

    • 移除冗余的文件内容读取操作,直接使用request.FILES中的UploadedFile对象保存,提升效率且减少出错概率。
    • 删除重复的form.save()调用,避免Post实例重复保存。
  2. Dropzone配置完善

    • 添加headers配置,确保CSRF令牌被正确携带,通过Django的CSRF验证。
    • 优化提交逻辑:区分有无上传文件的场景,保证表单和文件都能正确提交。
    • 监听queuecomplete事件,上传完成后自动跳转,避免用户重复操作。
  3. 模板读取已上传图片
    在文章详情页模板中,通过Post模型的related_name='images'关联,直接遍历展示图片:

{% for image in post.images.all %}
    <img src="{{ image.file.url }}" alt="Post image" class="img-fluid mb-3">
{% endfor %}

内容的提问来源于stack exchange,提问作者jmur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 20:42:22