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

时间:2018-07-25 03:27:43

标签: python django

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

注释(文本)表单是通过CreateView子文件夹在我的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中为class Photos_form(forms.Form):写些什么?如何将此类与我的class DescriptionCreate(CreateView)连接起来?

2 个答案:

答案 0 :(得分:0)

我在相同情况下使用FormSet SOAP

为图像模型声明FormSet

phpinfo();

我尝试将自定义代码重写为您的变体。 我想在您的示例中将… # 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 # templates <div id="img-form-template" style="display: none"> <!- Declare EMPTY FORM for dynamically rebuild user interface by jQuery, for example-> {{ formset.empty_form }} </div> ... <div id="my-images"> ... {{ formset.management_form }} {% for image_form in formset %} {{ image_form }} {% endfor %} </div> ... <script> ... <!- Any javascript code to dynamically create empty form based on template "#img-form-template" -> ... </script> 声明为创建模型实例是一个坏主意:django自动创建self.city

答案 1 :(得分:0)

我希望你找到了答案,我做了一些事情,但可能不是被推荐的答案;

我有一个页面用于上传多个图像,另一个页面用于查看图像,添加其他信息并完成该过程。在页面之间,我使用了会话传递父表ID,通过该父表ID,我将要上传的多个图像分组。

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

class UploadImages(LoginRequiredMixin,CreateView):

在get_context_data中,我执行以下操作(概述):

if "album_id" not in self.request.session:
        print("Creating a temporary album!")
        album = Album(
            owner = self.request.user,
            category_id = 6,#others
            privacy_id=3,#restricted
            status_id=8,#temporary file
            title="Temporary Album for " + self.request.user.get_full_name(),
            is_temp=True
        )

        album.save()

        self.request.session['album_id'] = album.id

context.update({
        'taid':album_id,
    })

    return context

当我从菜单重定向到该视图时,所有带有album_id的会话ID都会更清晰,这样,它将首次被调用。每次上传单个文件时,都会在form_valid内部调用此方法,因此最好先进行验证然后再创建。在HTML模板中,我使用此javascript变量在ajax调用中成功上传文件后保存重定向网址:

<script>
  var redirect_url = "{% url 'images:complete-upload' %}"
</script>

然后使用form_valid:

if self.request.is_ajax():
        album_id = self.request.session['album_id']

现在我可以访问album_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)
    }
  }

});

到目前为止,这已经为我完成了工作。我还没有弄清楚这是否是最佳实践。一旦完成渗透测试,大概一个月后,我就会知道(或其他人指出了此代码中的漏洞)。

在接收页面上,我从会话(get_context_data)中拾取album_id,然后将其删除以确保会话干净。

我希望这会有所帮助。