Python 如何使用CreateView在Django中上传多个文件?

Python 如何使用CreateView在Django中上传多个文件?,python,django,Python,Django,请帮帮我。我是Django新手,无法理解以下内容-我有CreateView的子类用于创建注释。我想创建一个项目,人们可以在其中留下他们的评论,并将文件(图像)附加到此评论。一个人应该有可能附加尽可能多的图像,因为他想一个文本评论形式。我在互联网上发现一个决定,我需要使用2个模型-1个模型用于文本评论+1个单独的模型用于图像。是这样吗 注释(文本)表单由CreateView的子类在my views.py中创建和处理。如何将图像的新单独模型与我的CreateView连接 models.py cla

请帮帮我。我是Django新手,无法理解以下内容-我有CreateView的子类用于创建注释。我想创建一个项目,人们可以在其中留下他们的评论,并将文件(图像)附加到此评论。一个人应该有可能附加尽可能多的图像,因为他想一个文本评论形式。我在互联网上发现一个决定,我需要使用2个模型-1个模型用于文本评论+1个单独的模型用于图像。是这样吗

注释(文本)表单由CreateView的子类在my views.py中创建和处理。如何将图像的新单独模型与我的CreateView连接

models.py

class Descriptions(models.Model):
…
city = models.ForeignKey(Cities, on_delete=models.CASCADE)
description = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.DO_NOTHING)
…
class Description_Photos(models.Model):
    image = models.ImageField(upload_to='images/', blank=True)
    description = models.ForeignKey(Descriptions, on_delete=models.CASCADE, related_name='photos')

forms.py

class DescriptionsForm(forms.ModelForm):
    class Meta:
        model = Descriptions
        exclude = []
        widgets = {'description': forms.Textarea(attrs={'cols':90})}

class Photos_form(forms.Form):
    photos = forms.FileField(widget=forms.FileInput(attrs={'multiple': True}))

views.py

class DescriptionCreate(CreateView):
    model = Descriptions
    form_class = DescriptionsForm
    template_name = 'countries/new_description.html'

    def get_success_url(self):
        return reverse('countries:descr', args=[self.kwargs['country_id'], self.kwargs['city_id']])

    def get_context_data(self, **kwargs):
        self.city = get_object_or_404(Cities, id=self.kwargs['city_id'])
        kwargs['city'] = self.city
        return super().get_context_data(**kwargs)

    def form_valid(self, form):
        form.instance.city = get_object_or_404(Cities, id=self.kwargs['city_id'])
        form.instance.owner = self.request.user
        messages.success(self.request, 'Your post has been added, thank you')
        return super().form_valid(form)

所以我的问题是,我应该在views.py中为
班级照片\u表单(forms.form):
写些什么?如何连接该类和我的
类描述创建(CreateView)

我用于相同情况的表单集

为图像模型声明表单集

…

# forms.py

class DescriptionsForm(forms.ModelForm):
    class Meta:
        model = Descriptions
        exclude = []
        widgets = {'description': forms.Textarea(attrs={'cols':90})}

class Photos_form(forms.Form):
    photos = forms.FileField(widget=forms.FileInput(attrs={'multiple': True}))


##### Declare FORMSET !!! ###
class BasePhotosFormSet(BaseModelFormSet):

    """By default, when you create a formset from a model, the formset
    will use a queryset that includes all objects in the model"""

    def __init__(self, *args, **kwargs):
        if 'city' in kwargs.keys():
            city = kwargs.pop('city')
        else:
            city = None
        super().__init__(*args, **kwargs)
        if city and isinstance(instance, Cities):
            self.queryset = Description_Photos.objects.filter(city=city)
        else:
            self.queryset = Description_Photos.objects.none()

# I usually declare formset for create operations and formset for update operations separately          
PhotosCreateFormSet = forms.modelformset_factory(Description_Photos, Photos_form,
                                                    fields=Photos_form.Meta.fields, extra=0,
                                                    formset=BasePhotosFormSet)


PhotosUpdateFormSet = forms.modelformset_factory(Description_Photos, Photos_form, can_delete=True,
                                              fields=PropertyImageForm.Meta.fields, extra=0,
                                              formset=BasePhotosFormSet)


#############

# views.py

class DescriptionCreate(CreateView):

    def __init__(self, **kwargs):
        self.object = None
        super().__init__(**kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.request.POST:
            images_formset = PhotosCreateFormSet(self.request.POST, self.request.FILES, city=self.object)
        else:
            images_formset = PhotosCreateFormSet(instance=self.object)
        context['formset'] = images_formset
        context['city'] = self.object
        return context
模板


{{formset.empty_form}}
...
...
{{formset.management_form}
{%formset%}中的图像形式为%
{{image_form}}
{%endfor%}
...
...
...
我已尝试将自定义代码重写为您的变体。
我想在您的示例中将
self.city
声明为创建模型实例是一个坏主意:Django自动创建
self.object
我希望您已经找到了答案,我做了一些事情,但可能不是清洁的或推荐的

我有一个页面用于上传多个图像,另一个页面用于查看图像、添加其他信息和完成过程。在页面之间,我使用session传递了一个父表ID,通过它我可以对上传的多个图像进行分组

下面是我上传图片的课程:

class UploadImages(LoginRequiredMixin,CreateView):
在get_context_data中,我执行以下操作(总结):

当我从菜单重新指向此视图时,所有具有album_id的会话id都会更清晰,这样它将第一次被调用。每次上载单个文件时,该方法将在form_valid内调用,因此,最好先进行验证,然后再进行创建。在HTML模板中,我使用以下javascript变量在成功上传文件后保存重定向url,即ajax调用:

<script>
  var redirect_url = "{% url 'images:complete-upload' %}"
</script>
现在,我可以访问相册_id,并且可以使用它保存多个图像,并将其分组到一个相册中:

lnk_album = AlbumPhotos(
            album_id = album_id,
            photo = self.object
        )

        lnk_album.save()
对每条消息执行此操作后,我的ajax调用将返回成功,在javascript文件中,我执行以下操作:

$("#fileupload").fileupload({
  dataType: 'json',
  sequentialUploads: true,  /* 1. SEND THE FILES ONE BY ONE */
  start: function (e) {  /* 2. WHEN THE UPLOADING PROCESS STARTS, SHOW THE MODAL */
    $("#modal-progress").modal("show");
  },
  stop: function (e) {  /* 3. WHEN THE UPLOADING PROCESS FINALIZE, HIDE THE MODAL */
    $("#modal-progress").modal("hide");

    //write code to re-direct
    window.location.replace(redirect_url);
  },
  progressall: function (e, data) {  /* 4. UPDATE THE PROGRESS BAR */
    var progress = parseInt(data.loaded / data.total * 100, 10);
    var strProgress = progress + "%";
    $(".progress-bar").css({"width": strProgress});
    $(".progress-bar").text(strProgress);
  },
  done: function (e, data) {
      console.log("completed file upload!")
    if (data.result.is_valid) {
        console.log("success!!")
    }
    else{
        console.log(e)
    }
  }

});
到目前为止,我已经完成了这项工作。我还没有弄清楚这是否是一个最佳实践。一旦我做了渗透测试,可能在一个月左右,完成这个应用后,我就会知道(或者其他人指出了这个代码中的漏洞)

在接收页面上,我从会话(获取上下文数据)中提取相册id,然后将其删除以确保会话干净


我希望这会有所帮助。

如果您需要django表单作为照片字段,只需将表单传递到上下文数据中,并将数据保存在
表单中即可。实际上你不需要有
照片\u表单
。最简单的方法是以html格式发送表单数据(使您的文件输入为html格式),并保存在Django官方文档中的
form\u valid
中。对于处理文件的单独模型,需要有表单:class FileFieldForm(forms.form):file\u field=forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple':True}))我不知道该怎么办,但这不是决定。我希望人们加载尽可能多的图像,因为他们想一个职位(1表)。一个人想在一篇文章中附上5张照片,另一个人可能想在一篇文章中附上7张照片。每次都有不同的数量。Formset允许附加有限数量(由参数“extra”设置)的图像。不是吗?不,额外的参数设置可见空表单的计数,我通常将额外设置为0,因为我喜欢通过Javascript动态操作表单。我可以公开我的上一个项目的代码,添加出租公寓的照片sitePavel,是的,请公开这个问题的Django代码。我完全不明白如何将CreateView和多个表单结合起来。非常感谢!将尝试解决此问题。您可以将extra>0设置为调试/实验视图模板
lnk_album = AlbumPhotos(
            album_id = album_id,
            photo = self.object
        )

        lnk_album.save()
$("#fileupload").fileupload({
  dataType: 'json',
  sequentialUploads: true,  /* 1. SEND THE FILES ONE BY ONE */
  start: function (e) {  /* 2. WHEN THE UPLOADING PROCESS STARTS, SHOW THE MODAL */
    $("#modal-progress").modal("show");
  },
  stop: function (e) {  /* 3. WHEN THE UPLOADING PROCESS FINALIZE, HIDE THE MODAL */
    $("#modal-progress").modal("hide");

    //write code to re-direct
    window.location.replace(redirect_url);
  },
  progressall: function (e, data) {  /* 4. UPDATE THE PROGRESS BAR */
    var progress = parseInt(data.loaded / data.total * 100, 10);
    var strProgress = progress + "%";
    $(".progress-bar").css({"width": strProgress});
    $(".progress-bar").text(strProgress);
  },
  done: function (e, data) {
      console.log("completed file upload!")
    if (data.result.is_valid) {
        console.log("success!!")
    }
    else{
        console.log(e)
    }
  }

});