问题描述
我正在尝试创建一个更新视图,其中包含一些内联表单集,但由于某种原因,我看到“id:此字段是必需的”。 & 当我单击更新按钮时,没有设置任何内联表单集值。字段本身实际上在模板中有值,所以我不确定为什么在尝试保存时内联表单集会是空的。
Models.py
class ProjectUpdateForm(forms.ModelForm):
class Meta:
model = Project
fields = ('name','details')
Views.py
class ProjectUpdateView(LoginrequiredMixin,UpdateView):
model = Project
template_name = 'home/project/project_update.html'
context_object_name = "project"
form_class = ProjectUpdateForm
def get_context_data(self,**kwargs):
ReviewChildFormset = inlineformset_factory(
Project,AdoptedBudgetReview,fields=('project','review'),can_delete=False,extra=0
)
itemNames = [{'item': item} for item in ['Concept & Feasibility','Planning & Design','Procurement','Delivery & Construction','Finalisation']]
EstimatedBudgetChildFormset = inlineformset_factory(
Project,EstimatedBudget,'item','cost','time'),formset=EstimatedInlineFormset,extra=0,widgets={'item': forms.Select(attrs={'disabled': True})},)
FutureExpenditureFormset = inlineformset_factory(
Project,FutureExpenditure,'byear','internalFunding','externalFundingSource','externalFunding'),)
PrevIoUsExpenditureFormset = inlineformset_factory(
Project,PrevIoUsExpenditure,)
initial = [{'priority': priority} for priority in Priority.objects.all()]
PriorityChildFormset = inlineformset_factory(
Project,ProjectPriority,'priority','score'),widgets={'priority': forms.Select(attrs={'disabled': True})},)
context = super().get_context_data(**kwargs)
if self.request.POST:
context['adoptedreviews'] = ReviewChildFormset(self.request.POST,instance=self.object)
context['estimatedbudget'] = EstimatedBudgetChildFormset(self.request.POST,initial=itemNames,instance=self.object)
context['futureexpenditure'] = FutureExpenditureFormset(self.request.POST,instance=self.object)
context['prevIoUsexpenditure'] = PrevIoUsExpenditureFormset(self.request.POST,instance=self.object)
context['priorities'] = PriorityChildFormset(self.request.POST,initial=initial,instance=self.object)
else:
context['adoptedreviews'] = ReviewChildFormset(instance=self.object)
context['estimatedbudget'] = EstimatedBudgetChildFormset(initial=itemNames,instance=self.object)
context['futureexpenditure'] = FutureExpenditureFormset(instance=self.object)
context['prevIoUsexpenditure'] = PrevIoUsExpenditureFormset(instance=self.object)
context['priorities'] = PriorityChildFormset(initial=initial,instance=self.object)
return context
def form_valid(self,form):
context = self.get_context_data()
adoptedreview = context["adoptedreviews"]
estimatedbudget = context["estimatedbudget"]
prioritycriteria = context["priorities"]
futureexpenditure = context["futureexpenditure"]
prevIoUsexpenditure = context["prevIoUsexpenditure"]
form.instance.creator = self.request.user
if adoptedreview.is_valid() and estimatedbudget.is_valid() and prevIoUsexpenditure.is_valid() and futureexpenditure.is_valid and prioritycriteria.is_valid():
self.object = form.save()
adoptedreview.instance = self.object
estimatedbudget.instance = self.object
futureexpenditure.instance = self.object
prevIoUsexpenditure.instance = self.object
prioritycriteria.instance = self.object
adoptedreview.save()
estimatedbudget.save()
prevIoUsexpenditure.save()
futureexpenditure.save()
prioritycriteria.save()
else:
return self.form_invalid(form)
return super(ProjectCreateview,self).form_valid(form)
模板
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Update Project</legend>
{{ form|crispy }}
</fieldset>
<h2>Adopted Budget Review</h2>
<!-- {{ adoptedreviews|crispy }} -->
<table class="table table-light">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">BR1</th>
<th scope="col">BR2</th>
<th scope="col">BR3</th>
<th scope="col">BR4</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Amount</th>
{{ adoptedreviews.management_form }}
{% for adrform in adoptedreviews.forms %}
{% for field in adrform.visible_fields %}
<td>
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
{% endfor %}
</tr>
</tbody>
</table>
<h2>Estimated Budget - Breakdown Yr1</h2>
<!-- {{ estimatedbudget|crispy }} -->
<table class="table table-light">
{{ estimatedbudget.management_form }}
<thead>
<tr>
<th scope="col">Item - Description</th>
<th scope="col">Anticipated % cost</th>
<th scope="col">Anticipated time - weeks</th>
</tr>
</thead>
{% for form in estimatedbudget.forms %}
<tr>
<td>
{{ form.errors }}
<h4>{{ form.item.value }}</h4>
{{ form.item.as_hidden }}
</td>
<td>
{{ form.cost }}
</td>
<td>
{{ form.time }}
</td>
</tr>
{% endfor %}
</table>
<h2>Future Project Expenditure</h2>
<!-- {{ futureexpenditure|crispy }} -->
<table class="table table-light">
{{ futureexpenditure.management_form }}
{% for form in futureexpenditure.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th scope="col">{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tbody>
<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 }}
{{ field }}
</td>
{% endfor %}
</tr>
</tbody>
{% endfor %}
</table>
<h2>PrevIoUs Project Expenditure</h2>
<table class="table table-light">
<!-- {{ prevIoUsexpenditure|crispy }} -->
{{ prevIoUsexpenditure.management_form }}
{% for form in prevIoUsexpenditure.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th scope="col">{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tbody>
<tr class="{% cycle row1 row2 %} prevIoUs_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 }}
{{ field }}
</td>
{% endfor %}
</tr>
</tbody>
{% endfor %}
</table>
<h2>Priority Criteria</h2>
<!-- {{ priorities|crispy }} -->
<table class="table table-light">
<tbody>
{{ priorities.management_form }}
{% for priority in priorities.forms %}
<tr>
<td>
{{ priority.priority.errors.as_ul }}
{% for value,name in priority.priority.field.choices %}
{% if value == priority.priority.value %}
<h4>{{ name }}</h4>
{% endif %}
{% endfor %}
{{ priority.priority.as_hidden }}
</td>
<td>
{{ priority.score.errors.as_ul }}
{{ priority.score }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update Project</button>
</div>
</form>
解决方法
无论何时手动渲染表单,都应该记住总是渲染它的隐藏字段,对于表单集/内联表单集更是如此,因为它会自动向表单添加一些隐藏字段.由于表单集正在更新多个实例,当然需要在表单集中存在一些东西来指示哪个实例是哪个,这是由这里的隐藏字段完成的。
因此您需要呈现表单集表单的隐藏字段:
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Update Project</legend>
{{ form|crispy }}
</fieldset>
<h2>Adopted Budget Review</h2>
<!-- {{ adoptedreviews|crispy }} -->
<table class="table table-light">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">BR1</th>
<th scope="col">BR2</th>
<th scope="col">BR3</th>
<th scope="col">BR4</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Amount</th>
{{ adoptedreviews.management_form }}
{% for adrform in adoptedreviews.forms %}
{% for hidden in adrform.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in adrform.visible_fields %}
<td>
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
{% endfor %}
</tr>
</tbody>
</table>
<h2>Estimated Budget - Breakdown Yr1</h2>
<!-- {{ estimatedbudget|crispy }} -->
<table class="table table-light">
{{ estimatedbudget.management_form }}
<thead>
<tr>
<th scope="col">Item - Description</th>
<th scope="col">Anticipated % cost</th>
<th scope="col">Anticipated time - weeks</th>
</tr>
</thead>
{% for form in estimatedbudget.forms %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<tr>
<td>
{{ form.errors }}
<h4>{{ form.item.value }}</h4>
{{ form.item.as_hidden }}
</td>
<td>
{{ form.cost }}
</td>
<td>
{{ form.time }}
</td>
</tr>
{% endfor %}
</table>
<h2>Future Project Expenditure</h2>
<!-- {{ futureexpenditure|crispy }} -->
<table class="table table-light">
{{ futureexpenditure.management_form }}
{% for form in futureexpenditure.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th scope="col">{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tbody>
<tr class="{% cycle row1 row2 %} formset_row">
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% 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 }}
{{ field }}
</td>
{% endfor %}
</tr>
</tbody>
{% endfor %}
</table>
<h2>Previous Project Expenditure</h2>
<table class="table table-light">
<!-- {{ previousexpenditure|crispy }} -->
{{ previousexpenditure.management_form }}
{% for form in previousexpenditure.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th scope="col">{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tbody>
<tr class="{% cycle row1 row2 %} previous_formset_row">
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% 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 }}
{{ field }}
</td>
{% endfor %}
</tr>
</tbody>
{% endfor %}
</table>
<h2>Priority Criteria</h2>
<!-- {{ priorities|crispy }} -->
<table class="table table-light">
<tbody>
{{ priorities.management_form }}
{% for priority in priorities.forms %}
{% for hidden in priority.hidden_fields %}
{{ hidden }}
{% endfor %}
<tr>
<td>
{{ priority.priority.errors.as_ul }}
{% for value,name in priority.priority.field.choices %}
{% if value == priority.priority.value %}
<h4>{{ name }}</h4>
{% endif %}
{% endfor %}
{{ priority.priority.as_hidden }}
</td>
<td>
{{ priority.score.errors.as_ul }}
{{ priority.score }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update Project</button>
</div>
</form>
此外,由于您有多个表单集,您应该为它们提供前缀以提供名称冲突(请参阅 Using more than one formset in a view):
if self.request.POST:
context['adoptedreviews'] = ReviewChildFormset(self.request.POST,instance=self.object,prefix='adoptedreviews_form')
context['estimatedbudget'] = EstimatedBudgetChildFormset(self.request.POST,initial=itemNames,prefix='estimatedbudget_form')
context['futureexpenditure'] = FutureExpenditureFormset(self.request.POST,prefix='futureexpenditure_form')
context['previousexpenditure'] = PreviousExpenditureFormset(self.request.POST,prefix='previousexpenditure_form')
context['priorities'] = PriorityChildFormset(self.request.POST,initial=initial,prefix='priorities_form')
else:
context['adoptedreviews'] = ReviewChildFormset(instance=self.object,prefix='adoptedreviews_form')
context['estimatedbudget'] = EstimatedBudgetChildFormset(initial=itemNames,prefix='estimatedbudget_form')
context['futureexpenditure'] = FutureExpenditureFormset(instance=self.object,prefix='futureexpenditure_form')
context['previousexpenditure'] = PreviousExpenditureFormset(instance=self.object,prefix='previousexpenditure_form')
context['priorities'] = PriorityChildFormset(initial=initial,prefix='priorities_form')
注意:您似乎有奇怪的 HTML(表格中有多个 tbody
元素??),而且您可能想要重新考虑这么多
页面中的表单集,这对于用户体验而言可能被认为是不利的(这
可能会真的让用户感到困惑,更不用说开发人员了
也)。理想情况下,一页应该为用户服务一个目的。