使用两个提交按钮将Django inlineformset保存为草稿

问题描述

我有一个有效的inlineformset。我试图添加第二个提交按钮,当单击该按钮时,将检查每个内联表单中的特定字段是否已填写,即,仅当单击第二个提交按钮时,此字段才成为必填字段。

问题是,当我单击第二个提交按钮时,不会出现验证错误,并且表单似乎仍然可以提交。我认为问题出在我的视野之内,即form_valid。我不确定if form.is_valid()失败时需要返回什么。

我正在自学编码,因此非常感谢您的帮助或指导。

Forms.py

class response_form_draft(forms.ModelForm):
    class Meta:
        name = response
        exclude = ['id_question','order']
    def __init__(self,*args,**kwargs):
        super(response_form_draft,self).__init__(*args,**kwargs)
        self.helper = FormHelper()
        self.helper.form_show_labels = False

class response_form_final(forms.ModelForm):
    class Meta:
        name = response
        exclude = ['id_question',**kwargs):
        super(response_form_final,**kwargs)
        self.helper = FormHelper()
        self.helper.form_show_labels = False
    def clean(self):
        data = self.cleaned_data
        resp = data['response']
        if resp == "":
            raise forms.ValidationError(('must not be blank'))


checklist_formset_draft = inlineformset_factory(checklist,response,form = response_form_draft,extra=0,can_delete=False,widgets={'comments': forms.Textarea(attrs={'cols': 7,'rows': 3,'style':'resize:none'})
                                                                                    })

checklist_formset_final = inlineformset_factory(checklist,form = response_form_final,'style':'resize:none'}),'response': forms.TextInput(attrs={'required':True})
                                                })

Views.py

class ChecklistUpdateView(LoginrequiredMixin,UpdateView):
    login_url = '/user/login'
    model = checklist
    form_class = checklist_form
    success_url = reverse_lazy('checklist:checklist_list')

    def get_context_data(self,**kwargs):
        data = super(ChecklistUpdateView,self).get_context_data(**kwargs)
        if self.request.POST:
            if 'complete' in self.request.POST:
                print("complete")
                data['question'] = checklist_formset_final(self.request.POST,instance=self.object)
            else:
                print("draft")
                data['question'] = checklist_formset_draft(self.request.POST,instance=self.object)
        else:
            data['question'] = checklist_formset_draft(instance=self.object)
        return data

    def form_valid(self,form):
        context = self.get_context_data()
        question = context['question']
        with transaction.atomic():
            self.object = form.save(commit=False)
            self.object.last_edit_by = str(self.request.user)
            self.object.last_edit_date = timezone.Now()
            if question.is_valid():
                question.instance = self.object
                question.save()

        return super(ChecklistUpdateView,self).form_valid(form)

HTML模板

{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}


<div class="container">

<form method="post">
  {% csrf_token %}
  <h1>{{ object.id_template.title }}</h1>
  {{ form.errors }}
  {{ form.entity|as_crispy_field }}

  {{ form.date_created.as_hidden }}
  {{ form.created_by.as_hidden }}
  {{ form.id_template.as_hidden }}
  {{ form.status.as_hidden }}
<div class="card">


<table id="table_id" class="table">
  <tbody>
    {{ question.management_form }}

    {% for form in question.forms %}
        {{ formset.errors }}
        {{ form.non_field_errors }}
      {% if forloop.first %}
          <thead class="thead-dark">
          <tr>
              {% for field in form.visible_fields %}
                  <th>{{ field.label|capfirst }}</th>
              {% endfor %}
              <th></th>
          </tr>
          </thead>
      {% endif %}

      <tr class="{% cycle row1 row2 %} formset_row">

                    {% for field in form.visible_fields %}
                        <td>
                            {# Include the hidden fields in the form #}
                            {% if forloop.first %}

                                {% for hidden in form.hidden_fields %}
                                    {{ hidden }}
                                {% endfor %}
                            {% endif %}
                            {{ field.errors.as_ul }}
                            {% if field.label == "Question" %}
                              <p>{{ form.question.value }}</p>
                              {{ field.as_hidden }}
                            {% elif field.label == "Response" %}
                              {{ field.as_hidden }}
                                <button id="Yes.{{ forloop.parentloop.counter0 }}" row="{{ forloop.parentloop.counter0 }}" class="ans {{ forloop.parentloop.counter0 }} btn btn-dark right">Yes</button>
                                <button id="No.{{ forloop.parentloop.counter0 }}" row="{{ forloop.parentloop.counter0 }}" class="ans {{ forloop.parentloop.counter0 }} btn btn-dark right">No</button>
                                <button id="N/a.{{ forloop.parentloop.counter0 }}" row="{{ forloop.parentloop.counter0 }}" class="ans {{ forloop.parentloop.counter0 }} btn btn-dark right">N/a</button>


                            {% else %}
                            {{ field|as_crispy_field }}
                            {% endif %}
                        </td>
                    {% endfor %}
                    <td>  </td>
                </tr>

{% endfor %}
</tbody>
</table>
</div>
{{ form.comments|as_crispy_field }}
  {{ form.audit|as_crispy_field }}
  <div class="form-submit-row" id="submit-row">
    <input class="btn btn-dark right" name="draft "type="submit" value="Save draft">
    <input class="btn btn-dark right" name="complete" type="submit" value="Complete">
    <a href="{% url 'checklist:checklist_delete' pk=object.id %}" class="btn btn-danger right">Delete</a>
  </div>
</form>
<br><br>

</div>

解决方法

表单有效时,

form_valid被激活。 django在类视图中自动检查checklist_form的有效性,而无需验证表单集。您可以在form_validform_invalid中添加自定义验证,但我会采取另一种方式。我会将formset放入您的基本表单(checklist_form)

类似的东西:

class checklist_form(forms.ModelForm):
    def __init__(*args,**kwargs):
       self.question= kwargs.pop("question")
       super()__.init__(*args,**kwargs)

    def clean(self):
       cleaned_data = super().clean()
       if not self.question.is_valid():
          self.add_error(None,"Have some formset errors")
       return cleaned_data

now表单仅在formset也有效的情况下才有效。然后在您的ChecklistUpdateView中,将创建表单集放入get_form_kwargs

    def get_form_kwargs(self):
        data = super().get_form_kwargs()
        if self.request.POST:
            if 'complete' in self.request.POST:
                data['question'] = checklist_formset_final(self.request.POST,instance=self.object)
            else:
                data['question'] = checklist_formset_draft(self.request.POST,instance=self.object)
        else:
            data['question'] = checklist_formset_draft(instance=self.object)
        return data

在那之后,您需要在html模板中使用form.question而不是question