我如何正确地保存django表单中的dropzone文件,并在需要时从DB中获取它?

s8vozzvw  于 2023-03-20  发布在  Go
关注(0)|答案(1)|浏览(177)

我正在尝试用我的django应用程序处理拖放上传,但面临着缺乏关于dropzone + django的实际信息。之前我只使用了多个上传,就像你在下面看到的,效果很好,但现在是处理拖放的时候了,因为它更方便。我把它放在我的主窗体里,但我完全不明白我应该如何保存这些文件,并获得他们从DB中的模板,当我需要它.也许,有人可以帮助我吗?不要太生气,我不是一个有经验的JS用户..

型号.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=[],
    )

查看次数.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)

表单.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',
            ...
        }

创建帖子.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>
mrwjdhj3

mrwjdhj31#

所以,对于那些也会遇到这种问题的人,我分享我的解决方案。模型没有受到影响,所以让我们直接跳到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“submit-all”,以便下面的脚本找到它并正确处理点击动作。由于某种原因,CSS选择器对我不起作用。它在控制台中引发了一个错误,我在那里找到了它。脚本本身没有改变太多,但这些行是为了重定向正常工作而添加的,因为Dropzone使用 AJAX 上传图像:

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

查看.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)

表单.py

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

    class Meta:
        model = Post
        ...

在表单中,我创建了一个带有隐藏小部件的“图像”文件字段。为了方便在html中找到它。
现在它起作用了!与标准方法相比,不需要太多的改变。祝你好运!

相关问题