Django的默认模板表单呈现({{form}})如何工作?

时间:2014-10-14 20:42:30

标签: python django django-forms django-templates

在Django中在模板中呈现表单的最基本方法是将表单实例添加到上下文中:

context['form'] = MyForm()

然后,在您的模板中,通过将其称为模板变量来渲染表单:

<form method="POST">
    {% csrf_token %}
    {{ form }}
</form>

呈现此模板时,{{ form }}将呈现为:

<label for="my_field">my_field:</label>
<input type="default_widget_for_field_type" name="my_field" />

表单中的每个字段都有一对。

我的问题是:表单和/或模板语言中的代码路径实际上是什么渲染?基于Django模板语言中的其他约定,我曾预期基础{{ form }}的Python为form(),很像{{ object.get_absolute_url }}最终为object.get_absolute_url(),但是当我实例化我的表单在shell中的实例并尝试调用它,我得到一个TypeError告诉我它不可调用。我看了一下Django源代码,试图弄清楚这是怎么做的,但我没有太多运气。


这是我的用例。我想为表示对一段内容的评论的模型创建一个ModelForm。它具有该内容模型的外键。每个页面上都有多个内容,因此我需要实例化ModelForm的多个未绑定副本,以便为每个内容创建注释。每个表单都将附加到页面上的内容对象,因此我希望外键是用户可编辑的字段。

这意味着我需要处理填充外键字段,因此模板可以访问需要设置的对象,因此从模板中将其作为隐藏表单字段进行操作是有意义的。外键给。但是,如果我将外键字段从ModelForm中删除,则模型将无法在表单验证中正确保存。我可以覆盖表单验证以添加隐藏字段,但我觉得更优雅的方法是将字段添加到ModelForm,然后覆盖ModelForm的渲染方法,这样它就不会不要试图渲染那个领域。然后我将在我的模板中手动添加该字段。

{% for piece_of_content in page_contents %}
    {# the content #}
    <p>Add your comment!</p>
    <form method="POST" action="{% url 'comment-create' %}">
        {% csrf_token %}
        {# the overridden rendering method won't render the foreign key field... #}
        {{ form }}
        {# then I add it manually #}
        <input type="hidden" name="commented_on" value="{{ piece_of_content.id }}" />
    </form>

然后我将“comment-create”的网址连接到CreateView,将其form_class设置为ModelForm,它将在没有任何额外输入的情况下完成其任务。

如果表单只是可调用的,就像我想的那样,那么我可以覆盖ModelForm上的__call__,并告诉它渲染所有外键字段。但ModelForm没有__call__,我无法弄清楚 完成的位置!该表单包含用于呈现各种其他配置的方法(as_pas_ulas_table),但我没有看到仅用于默认呈现。

2 个答案:

答案 0 :(得分:2)

包括{{ form }}{{ form.as_table }}相同。这是因为表单的__unicode__方法调用其as_table()方法。有关详细信息,请参阅outputting forms as HTML上的文档。

template variables and lookups上的文档解释了变量如何包含在模板中。如果属性可调用,则调用该方法。但是在您的情况下,表单实例不可调用,因此将显示表单的unicode表示。

如果您不希望用户编辑字段,我建议您将其从表单中排除并在视图中进行设置。用户可以篡改隐藏字段的值。

答案 1 :(得分:2)

您的问题的答案是,这只是表单的字符串表示形式:__unicode__()调用as_p()呈现表单。

但是,这实际上并不是这样做的。而不是尝试破解输出和验证,然后尝试插入值,您应该只从表单中排除外键。然后只需在保存时添加:您可以从表单发布到的URL中获取相关值,并将其添加到那里:

if form.is_valid():
    obj = form.save(commit=False)
    obj.content_id = value_from_url
    obj.save()