Django:Disabled Dropdown 不会将信息发送回 POST

Posted

技术标签:

【中文标题】Django:Disabled Dropdown 不会将信息发送回 POST【英文标题】:Django: Disabled Dropdown doesn't send information back to POST 【发布时间】:2012-07-29 17:49:20 【问题描述】:

我在模型表单中有一个下拉菜单,用户应该无法更改所选值。 我发现 disabled 确实可以满足我的需要。然而,这有一个奇怪的地方:

第一次打开表单 (GET) 时选择了该值,用户无法更改该值。这很棒:

但是,一旦unrelated field 出现验证错误并且 POST 将用户发送回相同的表单,之前的信息就会丢失。禁用的外键下拉列表不再包含任何值,非常烦人。

我做了一些研究,并在 *** 上发现了一些东西,似乎当禁用外键下拉小部件时,根本没有数据被发回。正如third answer here 解释的那样,可以覆盖验证以不为下拉字段抛出任何错误。但是,如果任何其他不相关的字段引发错误,则数据将丢失,因为禁用的下拉菜单从未首先将任何数据发送到 POST。

这是一个棘手的情况。

有没有办法将视图中的数据传递给 request.POST ?或者你有什么建议?我可以使用readonly 而不是disabled,这样可以,但是用户可以更改下拉菜单,这也很烦人。

有什么想法吗?非常感谢

编辑:

小修正:数据没有完全丢失。相反,选择被错误地设置为初始虚拟值。

    <select id="id_form-0-deal_type" name="form-0-deal_type" disabled="disabled">
      <option selected="selected" value="">---------</option>
      <option value="1">deal 1</option>
      <option value="2">deal 2</option>
    </select>

更新:

Francis 的解决方案看起来很有希望。所以我尝试了他的第二个建议,并在 html 中添加了一个隐藏的输入字段,并将正确的值传递给 POST。

现在的问题是如何进行。我试图像这样在表单集的表单查询字典中添加缺少的条目(以便设置正确的下拉值)

formset.forms[0].data['form-0-deal_type'] = formset.forms[0].data['form-0-hiddenfield'] 

但上面写着This QueryDict instance is immutable

唯一的其他方法是通过Initials 使用常规表单集进行设置。不幸的是,我正在使用模型表单集,doesn't support initials 用于现有表单。

如果没有其他解决方案,我开始将我的模型表单集重构为常规表单集。仍然开放的想法...

最终更新 + 解决方案:

没有必要将 modelformset 重构为常规 fomset。事实上,我非常不鼓励这样做,因为它本身会带来其他问题。 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)

这加上弗朗西斯的解决方案:

 formset.management_form 
  % for fs in formset %  
      fs.id  
     <input type="hidden" name="hidden- fs.prefix -deal_type" value="fs.deal_type.value" />
   fs.deal_type
% endfor %
% endif %

只是创造奇迹......享受:)

【问题讨论】:

"数据并没有完全丢失。而是选择错误地设置为初始虚拟值。" - 那就是那个字段没有被张贴的b/c。所以使用默认值 【参考方案1】:

它不是 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 
<input type="hidden" name="field_name" value="form.field_name.value" />

它不是很优雅,但它可以让你到达那里。

您还可以更进一步,编写一些 JS 来查找禁用的元素并在其后添加带有该元素名称和值的输入。

一些示例 JQuery:

//Untested, but you get the gist
$(':disabled').each(
    function()
    
        $(this).after('<input type="hidden" name="' + $(this).attr('name') + '" value="' + $(this).val() + '" />');
    
);

【讨论】:

谢谢弗朗西斯。很好的解决方案。请参阅我更新的问题以及一些详细信息。谢谢【参考方案2】:

好吧,您可以在模板中设置具有隐藏属性的元素,使用视图中的表单集来构建表单:

form.field.as_hidden

在视图内部,如果问题是数据丢失,您始终可以为适合您模型结构的字段设置初始值,因为它是外键。当然,您必须在提交之前验证表单,如果表单无效,您可以在必须始终填写的字段上使用初始值呈现它。

【讨论】:

我喜欢这个主意。我不明白隐藏的部分,因为我显然失去了默认选择。因此,我需要以某种方式将其发送回视图。我设法通过弗朗西斯关于额外隐藏输入字段的建议做到了这一点。从那里我实际上在考虑表单集上的首字母。 :) 请看看我更新的问题。谢谢:) 太棒了!我会将这个问题保留在我的收藏夹中,因为将来我可以处理类似的情况!【参考方案3】:

我认为这是一个 HTML 问题,而不是 Django,禁用的表单字段不会将它们的值发回,所以你失去了价值。

如果验证失败,是否可以将值重新绑定到字段?您可以尝试类似

if form.is_valid(): # All validation rules pass
    #save form, redirect, etc.
else:
    form.disabled_field = my_value
return render(request, 'contact.html', 'form': form,)

显然,您需要用模型中的正确数据替换字段名称和值。

【讨论】:

以上是关于Django:Disabled Dropdown 不会将信息发送回 POST的主要内容,如果未能解决你的问题,请参考以下文章

Semantic的Dropdown(下拉框)要怎么用

Django:未提交表单中的只读字段

python测试开发django-175.bootstrap导航-带下拉菜单的标签页标签页(nav-tabs)

docker IPv4 forwarding is disabled. 解决方法

如何将Django中列表的值传递给方法?

我无法从 JQuery ajax 调用中加载部分 Django 模板