将值呈现为文本而不是 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" />

&lt;form&gt; 标签内?还是我走错了路?

【问题讨论】:

【参考方案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 - 在模板中呈现日期字段

多对多字段的 Django 表单上的逗号分隔文本而不是多项选择

以自定义表单呈现模板中的各个字段

将 django 表单中的布尔模型字段显示为单选按钮而不是默认复选框

在 django 中检索表单字段属性

Django allauth 自定义登录表单未呈现自定义用户模型中的所有字段