Использование наборов форм для моей загрузки файлов не работает при обновлении представления на основе классов только при создании в django

#django #django-forms #django-class-based-views #inline-formset

#django #django-forms #представления на основе классов django #встроенный-formset

Вопрос:

Я использовал столько примеров в Интернете, сколько смог собрать, пытаясь заставить мои две простые модели иметь возможность создавать встроенный набор форм, позволяющий мне добавлять много файлов в технический чертеж. Это не работает, я могу добавить только один файл для создания, а обновление обновляет только модель Technical_Entry, а не файл…что само по себе выглядит забавно. Пользовательский интерфейс ona create показывает одно место для добавления файла, затем сохраняет всю запись и ее дочернюю запись. Это работает. При обновлении пользовательский интерфейс показывает файл, который был сохранен ранее..(отлично!) но затем есть еще два слота «выбрать файл» (случайные?), И добавление файла к ним ничего не делает при нажатии кнопки сохранения. Он не удаляет файл, ранее добавленный при создании, но также не сохраняет новый файл, добавленный в теперь три слота (один используется, два свободны). Поэтому обновление по какой-то причине не работает для файлов.

 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
 

Для загрузки с использованием набора форм. Хотя страница «отображается» в основном правильно, она не создает запись в модели 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 %}
 

И как выглядит пользовательский интерфейс при редактировании…

введите описание изображения здесь

Комментарии:

1. при создании вы смогли загрузить несколько изображений?

2. нет, это вообще не сработало. Поэтому я сосредоточился на создании create и просто заставил одну загрузку работать, что и делает! затем я понял, что второй шаг заключается в том, чтобы заставить работать возможность редактировать эту загрузку в представлении обновления, то есть то, что здесь не работает. Затем в будущем … шаг 3 позволяет мне загружать много изображений, а затем в конечном итоге удалять / изменять несколько изображений в будущем.

Ответ №1:

 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. При обновлении причина, по которой обновление не работает даже после изменения представлений, заключалась в том, что вы не передавали hidden fields . Вы не передавали id s файлов, поэтому ваши наборы форм не передавались .is_valid() , следовательно, обновления не было. Добавьте цикл for о скрытых полях, как показано ниже.

 {{ 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 внимание на то, что я добавляю about hidden fields .

Комментарии:

1. Сделал это дословно (отредактированный OP). По-прежнему нет кубиков. Опубликовал снимок экрана того, как пользовательский интерфейс выглядит при редактировании…

2. спасибо за скриншот. Итак, 1) похоже, что экземпляр работает, потому что вы не видите созданный файл. 2) какие вещи не работают?

3. Создание работает! Я тоже могу опубликовать снимок экрана. Здесь опубликовано обновление view…it заполняет поля, как и должно быть, из базы данных, если я изменяю поле, оно действительно учитывает это изменение и отражается в базе данных. Он знает, что пытается отредактировать файл … есть ‘current’, указывающий на файл, который я загрузил при создании … но если я изменю файл, он фактически не будет изменен в БД или не появится новый файл на диске.

4. Дополнительно… Я бы не хотел так сильно меняться, как удалять и добавлять больше (произвольное их количество) Таким образом, редактирование части файла просто не работает, и даже если это сработало и позволило мне измениться… это все еще не окончательное воплощение, которое мне нужно.

5. просто чтобы быть уверенным, вы изменили последнюю строку updateview, верно?