如何从现有的 django 表单中正确保存 dropzone 文件并在需要时从数据库中获取它?

问题描述 投票:0回答:1

我正在尝试使用我的 django 应用程序处理拖放上传,但缺少有关 dropzone + django 的实际信息。以前我只使用多重上传,如下所示,效果很好,但现在是处理拖放操作的时候了,让它更方便。我将它处理为在我的主窗体中,但我完全不明白我应该如何保存这些文件并在需要时从模板中的数据库中获取它们。也许,有人可以帮我吗?不要对我太生气,我不是一个有经验的 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()
            for img in request.FILES.getlist('images'):
                data = img.read()
                new_file = PostImages(post=new_post)
                new_file.file.save(img.name, ContentFile(data))
                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):
    # COMMENT IT CAUSE I ASSUME TO USE DROPZONE FIELD WITH THIS NAME
    # 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,
      init() {
        var myDropzone = this;
        this.element.querySelector("[type=submit]").addEventListener("click", function(e){
          e.preventDefault();
          e.stopPropagation();
          myDropzone.processQueue();
        });
      }
    });
</script>
python django dropzone.js dropzone
1个回答
0
投票

所以,对于那些也将面临这种问题的人,我分享了我对该问题的有效解决方案。模型没有受到影响,所以让我们直接进入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>
        <button id="submit-all" class="btn btn-primary">Create</button>
    </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: 30,
      acceptedFiles: '.png, .jpg, .jpeg',
      uploadMultiple: true,
      parallelUploads: 20,
      autoProcessQueue: false,
      init() {
        var myDropzone = this;
        this.element.querySelector("#submit-all").addEventListener("click", function(e){
          e.preventDefault();
          e.stopPropagation();
          myDropzone.processQueue();
        });
        this.on("success", function(file, response) {
            window.location.href=JSON.parse(file.xhr.response).url
        });
      }
    });
</script>

我已经替换了引导程序按钮并为其指定了一个“提交所有”的 ID,以便下面的脚本找到它并正确处理点击操作。由于某些原因,CSS 选择器对我不起作用。它在我发现它的控制台中引发了一个错误。脚本本身并没有太大变化,但是添加了这些行是为了使重定向正常工作,因为 Dropzone 使用 AJAX 上传图像:

this.on("success", function(file, response) {
    window.location.href=JSON.parse(file.xhr.response).url

view.py

    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()
            files = [request.FILES.get(f'images[{i}]') for i in range(0, len(request.FILES))]
            for img in files:
                data = img.read()
                new_file = PostImages(post=new_post)
                new_file.file.save(img.name, ContentFile(data))
                new_file.save()
            messages.success(request, self.success_message)
            link = reverse('profile_detail', kwargs={'slug': request.user.slug})
            response = {'url': link}
            return JsonResponse(response)
        else:
            messages.error(request, 'Something went wrong!')
        return redirect(self.success_url)

在视图中,我添加了这一行以获取图像并在下面进行处理:

files = [request.FILES.get(f'images[{i}]') for i in range(0, len(request.FILES))]

我处理图像的方式完全没有改变,但现在我返回 JsonResponse:

link = reverse('profile_detail', kwargs={'slug': request.user.slug})
response = {'url': link}
return JsonResponse(response)

forms.py

class PostCreationForm(ModelForm):
    images = forms.FileField(label='', required=False, widget=forms.HiddenInput(attrs={'multiple': True}))

    class Meta:
        model = Post
        ...

在表单中,我创建了一个带有隐藏小部件的“图像”文件字段。为了 dropzone 在 html 中找到它。

现在可以了!与标准方法相比,不需要太多更改。祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.