django formset 未验证,因为需要 ID
Posted
技术标签:
【中文标题】django formset 未验证,因为需要 ID【英文标题】:django formset not validating because ID is required 【发布时间】:2018-08-08 03:10:09 【问题描述】:我的视图从模板接收模型表单集,但它没有通过验证,声称需要 ID。到目前为止,我对表单的使用从未出现过这个问题,而且我也从未需要传递 ID。
这是我的观点的简化版本:
def BudgetView(request):
import pdb
pdb.set_trace()
if request.user.is_authenticated:
U=request.user
#initalize formset factories
ItemFormSet = modelformset_factory(Item, fields=(blabla), extra=0)
CatFormset=modelformset_factory(BudgetCatagory, fields=(blabla), extra=0)
#initalize Constants
InitiateConstants(CatagoryItemsList)
if request.method=='POST':
FormsetItem=ItemFormSet(request.POST,initial=Item.objects.filter(budgetcatagory__user_id=U.id).values())
FormsetCat=CatFormset(request.POST)
if FormsetItem.is_valid():
-bla
-bla
-bla
return redirect('/HighLevelInput')
else:
#populate
I=Item.objects.filter(budgetcatagory__user_id=U.id)
C=BudgetCatagory.objects.filter(user_id=U.id)
#initiate initial catagories and items for new user
if (not I.exists()) or (not C.exists()):
Item.objects.filter(budgetcatagory__user_id=U.id).delete()
BudgetCatagory.objects.filter(user_id=U.id).delete()
InitiateNewUser(U)
I=Item.objects.filter(budgetcatagory__user_id=U.id)
C=BudgetCatagory.objects.filter(user_id=U.id)
FormsetItem=ItemFormSet(queryset=I)
FormsetCat=CatFormset(queryset=C)
return render(request,'getdata/budgetmachine.html', 'FormsetItem':FormsetItem, 'FormsetCat':FormsetCat )
else:
return redirect('/login')
is_valid
返回False
,原因我上面已经提到了。
有什么想法吗?
根据要求,以下是is_valid
检查返回的错误:
(Pdb) FormsetItem.errors
['id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'name': ['This field is required.'], 'detail': ['This field is required.'], 'layout': ['This field is required.'], 'unit': ['This field is required.'], 'unit_description': ['This field is required.'], 'parent': ['This field is required.'], 'enName': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'name': ['Ensure this value has at most 30 characters (it has 32).'], 'parent': ['Ensure this value has at most 30 characters (it has 32).'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.'], 'id': ['This field is required.']]
这是我的模板:
% block body %
<div class="container" style="width:80%">
<form method="post">
% csrf_token %
FormsetItem.management_form
FormsetCat.management_form
<table>
<tr>
<th>פריט</th>
<th>מחיר מתוקצב</th>
<th>מיקום מחיר</th>
<th>רמת פירוט</th>
<th>רמת פירוט</th>
</tr>
<!--unpacks the item dictionary into formsets -->
% for CatForm in FormsetCat %
<tbody onmouseenter="ToggleDisable(' CatForm.enName.value')" onmouseleave="ToggleDisable(' CatForm.enName.value')">
% for ItemForm in FormsetItem %
% if ItemForm.parent.value == CatForm.name.value %
% if ItemForm.layout.value == 'normal' %
% include 'getdata/normalBudgetLayout.html' with form=ItemForm itemCount=forloop.counter0 catagoryCount=forloop.parentloop.counter0 %
% elif ItemForm.layout.value == 'choice' %
% include 'getdata/choiceBudgetLayout.html' with form=ItemForm itemCount=forloop.counter0 catagoryCount=forloop.parentloop.counter0 %
% endif %
% endif %
% endfor %
<tr class="txt_center Row_ CatForm.enName.value" style="line-height:4em; background:Silver;">
<td>
<a onclick="ToggleDisable(' CatForm.enName.value')">
CatForm.name.value
<span style="float:left;">
<i class="fa fa-caret-down CatForm.enName.value" style="font-size:30px; padding:7px;"></i>
<i class="fa fa-caret-up CatForm.enName.value" style="font-size:30px; padding:7px;" hidden></i>
</span>
<!--/a-->
</td>
<td> CatForm.catagory_cost </td>
<td>TBD</td>
<td> CatForm.detail.value </td>
<td></td>
</tr>
</tbody>
% endfor %
</table>
<br />
<br />
<br />
<button type="submit" >Submit</button> <br />
<br />
</form>
</div>
% endblock %
谢谢
【问题讨论】:
请显示确切的错误。请注意,在 POST 块中传递initial
根本没有任何作用。为什么不像在 else 块中那样传递 queryset
呢?
新的,所以我每天都在学习新东西......我想使用一个查询集,但我读到初始只需要一个字典列表,而查询集需要一个查询集是对象。另外,我读到使用 initial 启动请求中的数据之间的比较,并且只更新已更改或添加的内容....将尝试您的观点,谢谢。但是问题仍然存在......它没有给我一个错误,只是 is_valid 返回 false 并且错误字段显示 id 是必需的。
您仍然需要显示该错误字段包含的内容。你也应该展示你的模板。但是我对您关于初始/查询集的观点感到非常困惑。在非 POST 情况下,您应该始终传递一个查询集,并且只传递初始值(如果您需要它)。
你的意思是这样的:FormsetItem=ItemFormSet(request.POST, queryset=Item.objects.filter(budgetcatagory__user_id=U.id)) ??
【参考方案1】:
在这种情况下,错误消息非常清楚:您必须呈现“id”字段,否则 POST 将不包含每条记录的主键值。
我建议使用crispy forms 并让它呈现整个表单集或手动呈现模板中的字段。 在第一种情况下,你会有这样的东西:
% load crispy_forms_tags %
<form action="post" ...>
% crispy formset %
</form>
否则:
<form action="post" ...>
<table>
<tbody>
% for form in formset %
<tr>
<td> form.field1 </td>
<td> form.field2 </td>
<td class="hidden"> form.id </td>
</tr>
</tbody>
</table>
</form>
【讨论】:
【参考方案2】:ModelFormsets
需要 form.id
。它呈现为隐藏字段。您将需要使用这两个表单集来实现它。
% for form in formset %
% for hidden in form.hidden_fields %
hidden
% endfor %
<!-- form.visible fields go here -->
% endfor %
【讨论】:
另外,好像使用management_form
会出现这个问题。因为management_form
表示你会管理所有的,所以隐藏字段也需要管理。
另见@j-a-n-u-s answer below【参考方案3】:
作为@unixo 答案的补充,简单地说:
form.id
没有任何周围的 HTML 标记,将在呈现模板时转换为以下内容(name
、value
和 id
的值将由您的 formset_factory
生成):
<input type="hidden" name="form-1-id" value="2" id="id_form-1-id">
只要确保它缩进到 for form in formset
循环中即可。
这意味着您不需要添加class="hidden"
,除非您对隐藏字段有特定的处理方式。
【讨论】:
此解决方案适用于标准解决方案(循环通过隐藏字段)没有的地方。惊人的!它为我解决了一个非常棘手的问题。以上是关于django formset 未验证,因为需要 ID的主要内容,如果未能解决你的问题,请参考以下文章
需要在 Django Formset 中有一个必填字段和可选字段
如何在 Django 中根据需要为 formset_factory 设置每个字段(如何验证表单集中的空白表单)