Django: 禁用下拉菜单无法将信息发送回POST
Django: 禁用下拉菜单无法将信息发送回POST
我有一个模型表单中的下拉菜单,用户不应该能够更改所选的值。我发现 disabled
语句确实可以做到我需要的事情。但是有一个奇怪的问题:
第一次打开表单(GET)时,值已被选择,用户不能更改值。这是很好的:
但是,一旦存在与 不相关的字段
相关的验证错误并且 POST 将用户返回到相同的表单,先前的信息将丢失。已禁用的外键下拉菜单不再包含任何值,这非常令人烦恼。
我进行了一些研究,发现了stackoverflow上的一些内容,似乎当外键下拉菜单小部件被禁用时,根本不会返回任何数据。虽然验证可以被重写以不对下拉字段抛出任何错误,正如这里的第三个答案所解释的那样。但是如果任何其他不相关的字段抛出错误,则数据将丢失,因为第一次已禁用的下拉菜单根本没有发送任何数据到POST。
这是一个棘手的情况。
有没有一种方法可以将数据传递到请求.POST中的视图中?或者您有什么建议?我可以使用 readonly
而不是 disabled
,这将起作用,但是用户仍然可以更改下拉菜单,这也很烦人。
有什么想法吗?非常感谢
编辑:
小修正:数据并没有完全丢失。相反,选择是错误地设置为初始虚拟值。
更新:
Francis的解决方案看起来非常有前途。因此,我尝试了他的第二个建议并在html中添加了一个隐藏的输入字段,并将正确的值传递到POST中。
问题现在是如何继续。我尝试添加表单集的表单查询字典中缺失的条目(以便设置正确的下拉列表值):
formset.forms[0].data['form-0-deal_type'] = formset.forms[0].data['form-0-hiddenfield']
但它说此QueryDict实例不可变
唯一 的其他解决办法就是通过表单集的初始值进行设置。可的确实现我正在使用modelformsets,它对现有表单不支持初始值。
如果没有其他解决方案,我将开始将我的modelformset转换为正常的表单集。但还是希望有其他的解决方案。
最终更新+解决方案:
没有必要将modelformset重构为常规表单集。事实上,我强烈不建议这样做,因为这会带来其他问题。modelformsets可以为您处理一切并填充缺少的部分。
实际问题是QueryDict是不可变的,但是这可以通过复制它们轻松解决:
formset = deal_formset(request.POST, queryset=formset_query) if formset.is_valid(): pass else: new_post = request.POST.copy() deal_types = dict() for k,v in new_post.items(): if k.startswith('hidden'): deal_types[k[7:]]= v for k,v in deal_types.iteritems(): new_post[k] = v formset = deal_formset(new_post, queryset=formset_query)
加上Francis的解决方案:
{{ formset.management_form }} {% for fs in formset %} {{ fs.id }} {{fs.deal_type}} {% endfor %} {% endif %}
真的可以创造奇迹...享受吧 🙂
这不是一个Django的问题,而是一个HTML的问题。禁用的表单元素不会被表单发送。
[该元素]不能接收用户输入,其值也不会随表单一起提交。
http://www.w3.org/TR/html401/interact/forms.html#h-17.12.1 和 http://www.w3schools.com/tags/att_input_disabled.asp
如果是文本框/文本区域,你可以使用 readonly
http://www.w3schools.com/tags/att_input_readonly.asp
还有一种方法,可以将值以明文显示,并将其提交为隐藏字段.....
{{ form.field_name.label_tag }} {{ form.field_name.value }}
这并不是很优雅,但可以解决你的问题。
你还可以进一步编写一些JS代码,查找禁用的元素,并在后面添加该元素的名称和值的输入。
一些样例JQuery:
//Untested, but you get the gist $(':disabled').each( function() { $(this).after(''); } );