将值呈现为文本而不是 Django 表单中的字段
Posted
技术标签:
【中文标题】将值呈现为文本而不是 Django 表单中的字段【英文标题】:Rendering a value as text instead of field inside a Django Form 【发布时间】:2010-11-11 04:04:01 【问题描述】:有没有简单的方法让Django将myform.name
渲染为
John Smith
而不是
<input id="id_name" name="name" value="John Smith" />
在<form>
标签内?还是我走错了路?
【问题讨论】:
【参考方案1】:这是上面@Matthew_Schinkel 建议的方法,使用 Django 2.2 和 python 3。
from django.utils.safestring import mark_safe
class PlainTextWidgetWithHiddenCopy(forms.Widget):
def render(self, name, value, attrs, renderer=None):
if hasattr(self, 'initial'):
value = self.initial
return mark_safe(
(str(value) if value is not None else '-') +
f"<input type='hidden' name='name' value='value'>"
)
这是一个自定义小部件,它将字段的内容呈现为纯文本,后跟一个 html 标记,该标记创建一个与原始字段具有相同名称和值的隐藏字段。
这意味着除了向用户显示的值之外,它还由浏览器保存并继续发送到处理提交表单的视图。
如果表单 POST 到自身,这将特别方便,否则纯文本数据会因为字段的 initial
值尚未设置而消失。
例如,如果您的表单包含:
my_field = forms.IntegerField(
widget=PlainTextWidgetWithHiddenCopy,
initial=12345)
那么该字段将呈现为以下html:
12345<input type='hidden' name='my_field' value='12345'>
当表单提交时,相应视图接收到的POST数据会包括:
'my_field': '12345'
这意味着如果视图现在重新呈现表单,那么 my_field
的值将再次设置为 12345
,就像请求是 GET
一样。
正如 Matthew 在他随后的评论中正确指出的那样,这种方法并不能有效防止用户更改在隐藏字段中发回的数据。 “所有用户输入都是邪恶的”。
【讨论】:
【参考方案2】:老话题了,不过我觉得还是有人来的。
你也可以这样做:
from django.utils.safestring import mark_safe
class PlainTextWidget(forms.Widget):
def render(self, _name, value, _attrs):
return mark_safe(value) if value is not None else '-'
在你的表单中
class SomeForm(Form):
somename = forms.CharField(widget=PlainTextWidget)
在 Django 2.1+ 下,您需要以下内容:
from django.utils.safestring import mark_safe
class PlainTextWidget(forms.Widget):
def render(self, name, value, attrs=None, renderer=None):
return mark_safe(value) if value is not None else '-'
【讨论】:
def render(self, name, value, attrs):
在 django 1.10 中(?不确定它是否在其他版本中,或者为什么我的版本不需要下划线?)所以没有 [_name 和 _attrs]【参考方案3】:
<form>
% for field in form %
field.label : field.value
% endfor %
</form>
看看这里Form fields和Working with forms
【讨论】:
谢谢 - 我看到了 .label 但没有看到 .initial。奇怪的是,“使用表单”文档中甚至没有提到 .initial。 .initial 仅在第一次显示表单时有效,对吗?例如,如果出现错误并且您重新提交表单,根据我的经验,不会有首字母。 在 Django 术语中,这只适用于未绑定的表单。如果您希望它同时使用未绑定和绑定表单怎么办?【参考方案4】:我认为这就是你想要的: http://code.djangoproject.com/ticket/10427
我修补了我的 django,瞧……
【讨论】:
【参考方案5】:为什么不使用 field.data ?
【讨论】:
因为它应该在不在模板中的视图中完成(在模板中是循环)【参考方案6】:另外,别忘了你也可以myform.instance.name
【讨论】:
这是什么?它记录在哪里? form.instance 返回绑定表单所代表的对象。它在此处的文档中:docs.djangoproject.com/en/dev/topics/forms/modelforms/… 我还应该提到这仅适用于模型表单 啊,谷歌应用引擎不支持ModelForm,所以我们使用Form。【参考方案7】:您还可以使用新的小部件:我这样做是为了创建一个小部件,该小部件创建一个日期的文本显示,以及一个包含相同日期的隐藏表单,以便用户可以看到它,但他们无法改变它。
这是一个初始(仍在测试/待清理)版本:
class DayLabelWidget(forms.Widget):
def render(self, name, value, attrs):
final_attrs = self.build_attrs(attrs, name=name)
if hasattr(self, 'initial'):
value = self.initial
if type(value) == type(u''):
value = datetime.date(*map(int, value.split('-')))
return mark_safe(
"%s" % value.strftime("%A (%d %b %Y)")
) + mark_safe(
"<input type='hidden' name='%s' value='%s' />" % (
name, value
)
)
def _has_changed(self, initial, data):
return False
然后在字段中将其用作(widget=DayLabelWidget,)
。
【讨论】:
这种方法对我来说非常有用,因为除了显示值的“普通”版本外,它还创建了一个副本,在表单发布时传递。我对其进行了调整以制作一个更通用的版本(请参阅我的答案进一步向下) 请记住,恶意用户很容易更改此值。您可能想让表单字段返回它的初始值。 我赞成。像这样的技术对于在表示层中保持状态非常有帮助,但是如果要在应用层使用,则必须彻底验证从用户表单或会话发回的任何数据项。以上是关于将值呈现为文本而不是 Django 表单中的字段的主要内容,如果未能解决你的问题,请参考以下文章
多对多字段的 Django 表单上的逗号分隔文本而不是多项选择