仅在 django 中创建基于更新 class 的视图时,将表单集用于我的文件上传不起作用

Using formsets for my fileupload does not work when doing an update class based view only on create in django

我在网上使用了尽可能多的示例,试图让我的两个简单模型能够执行内联表单集,从而允许我将许多文件添加到技术绘图中。 这是行不通的,我只能为创建添加一个文件,而更新只能更新 Technical_Entry 模型,而不是文件……这本身就很有趣。 UI ona create 显示一个地方添加一个文件,然后保存整个记录和它的子记录。这样可行。 更新后,UI 显示了之前保存的文件..(太棒了!)但随后又多了两个 'choose file' 插槽(随机的?)并在单击保存时将文件添加到这些插槽中什么都不做.它不会删除先前在创建中添加的文件,但它也会 不保存添加到现在三个插槽中的新文件(一个已用,两个可用)。因此出于某种原因更新对文件不起作用。

class Technical_Entry(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    ema = models.ForeignKey(EMA, on_delete=models.CASCADE)
    system = models.ForeignKey('System', on_delete=models.CASCADE) # are SYSTEMS RELATED TO SUBSYSTEMS OR JUST TWO GROUPS?  
    sub_system = models.ForeignKey(SubSystem, on_delete=models.CASCADE)

    drawing_number = models.CharField(max_length=200)
    drawing_title = models.CharField(max_length=255)
    engineer = models.CharField(max_length=200)
    vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)

    date_drawn = models.DateField()
    ab = models.BooleanField()



class Technical_Entry_Files(models.Model):
    tech_entry = models.ForeignKey(Technical_Entry, on_delete=models.CASCADE)
    file = models.FileField(upload_to='techdb/files/')

    def __str__(self):
        return self.tech_entry.drawing_number

使用表单集上传。虽然页面 'displays' 大部分是正确的,但它并没有在 Technical_Entry_Files 模型中创建记录。

相关forms.py:

class FileUploadForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(FileUploadForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()  
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-lg-4'
        self.helper.field_class = 'col-lg-8'
    
    class Meta:
        model = Technical_Entry_Files
        fields = ('file',)

TechFileFormSet  = inlineformset_factory(Technical_Entry, Technical_Entry_Files, form=FileUploadForm, extra=1, max_num=15)



class Technical_EntryForm(forms.ModelForm):



    def __init__(self, *args, **kwargs):
        super(Technical_EntryForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()  
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-lg-4'
        self.helper.field_class = 'col-lg-8'
        self.helper.add_input(Submit('submit', 'Submit'))

    class Meta:
        model = Technical_Entry
        fields = ('category', 'ema', 'system', 'sub_system', 'drawing_number', 'drawing_title', 'engineer', 'vendor', 'date_drawn', 'ab')


        widgets = {
            'date_drawn':DateInput(attrs={
            'class':'datepicker form-control',        
            'id' : 'datetimepicker2',
            'tabindex' : '1',
            'placeholder' : 'MM/DD/YYYY hh:mm',          
            'autocomplete':'off',
            }, format='%m/%d/%Y'),

            'system' : Select(attrs={'tabindex':'2'}),
        }

相关views.py:

class TechEntryCreateView(LoginRequiredMixin, CreateView):
    print ("we are here")
    model = Technical_Entry
    form_class = Technical_EntryForm
    template_name = 'techdb/tech_entry_form.html'
    print(template_name)
    success_url = '/techentry_add'

    def get_context_data(self, **kwargs):
        data = super(TechEntryCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            data['file_upload'] = TechFileFormSet(self.request.POST, self.request.FILES)
        else:
            data['file_upload'] = TechFileFormSet()
        return data


    def form_valid(self, form):
        context =self.get_context_data()
        file_upload = context['file_upload']
        with transaction.atomic():
            self.object = form.save()

            if file_upload.is_valid():
                file_upload.instance =self.object
                file_upload.save()
        return super(TechEntryCreateView, self).form_valid(form)


class TechEntryUpdateView(LoginRequiredMixin, UpdateView):                                                                                             

    model = Technical_Entry
    form_class = Technical_EntryForm
    template_name = 'techdb/tech_entry_form.html'
    success_url = '/'
                                                                                             
                                                                                         

    def get_context_data(self, **kwargs):                
        context = super(TechEntryUpdateView, self).get_context_data(**kwargs)

        if self.request.POST:
            context["file_upload"] = TechFileFormSet(self.request.POST, self.request.FILES,instance=self.object)
        else:
            context["file_upload"] = TechFileFormSet(instance=self.object)    
        return context

    def form_valid(self, form):
        context = self.get_context_data()
        file_upload = context["file_upload"]
        self.object = form.save()
        if file_upload.is_valid():
            file_upload.instance =self.object
            file_upload.save()
        return super(TechEntryUpdateView, self).form_valid(form)

和 tech_entry_form.html:

{% extends 'base.html' %}


{% load static %}

{% block page-js %}

<script>
    $('.link-formset').formset({
        addText: 'add file',
        deleteText: 'remove',        
    });
</script>
{% endblock %}

{% block content %}

<main role="main" class="container">

      <div class="starter-template">
        <h1>New Tech Entry</h1>
      </div>

    <h2> Details of Technical Entry </h2>
     <div class="row">
      <div class="col-sm">
       <form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
                {{ form.as_p }}

                <h2> Files </h2>
                {{ file_upload.management_form }}
                {% for upload_form in file_upload.forms %}
                  <div class="link-formset">
                    {{ upload_form.file }}        
                  </div>
                 {% endfor %}

               
                <input type="submit" value="Save"/><a href="{% url 'tech_database:index' %}">back to the list</a>
            </form>
        </div>
       </div>
     </div>
    </main><!-- /.container -->


{% endblock %}

编辑时 UI 的样子...

class TechEntryUpdateView(LoginRequiredMixin, UpdateView):                                                                                             

    model = Technical_Entry
    form_class = Technical_EntryForm
    template_name = 'techdb/tech_entry_form.html'
    success_url = '/'
                                                                                             
    #log_entry_class = Technical_EntryForm(Technical_Entry) #removed
                                                                                         
    def get_context_data(self, **kwargs):                
        context = super(TechEntryUpdateView, self).get_context_data(**kwargs)
        #self.object = self.get_object() #removed

        if self.request.POST:
            context["file_upload"] = TechFileFormSet(self.request.POST, self.request.FILES,instance=self.object)
        else:
            context["file_upload"] = TechFileFormSet(instance=self.object)

        return context

    def form_valid(self, form):
        context = self.get_context_data()
        file_upload = context["file_upload"]
        self.object = form.save()
        if file_upload.is_valid():
            file_upload.instance =self.object
            file_upload.save()
        #return super().form_valid(form)
        return super(TechEntryUpdateView, self).form_valid(form) #replaced old one

更新 1.为了创建时可以添加多个文件,

TechFileFormSet  = inlineformset_factory(Technical_Entry, Technical_Entry_Files, form=FileUploadForm, extra=4, max_num=4)

# note I changed to extra=4, if you always want to have only 4 files, then also change to max_num=4

2. update的时候,修改views后更新还是不行是因为你没有通过 hidden fields。您没有传递文件的 id,因此,您的表单集没有传递 .is_valid(),因此没有更新。添加关于隐藏字段的循环,如下所示。

{{ file_upload.management_form }}
   {% for upload_form in file_upload.forms %}

      {% for hidden in upload_form.hidden_fields %}
            {{hidden}}
      {% endfor %}

             <div class="link-formset">
                    {{ upload_form.file }}        
                  </div>
                 {% endfor %}

#注意我加的for loop关于hidden fields