【问题标题】:How to render django form field in template如何在模板中呈现 django 表单字段
【发布时间】:2011-12-30 17:55:04
【问题描述】:

我想创建一个页面,其中包含用户列表和复选框,以表明用户是否被选中,这将对所选用户应用一些操作。 我创建了一个如下所示的表单类:

#in forms.py
class UserSelectionForm(forms.Form):
    """form for selecting users"""
    def __init__(self, userlist, *args, **kwargs):
        self.custom_fields = userlist
        super(forms.Form, self).__init__(*args, **kwargs)
        for f in userlist:
            self.fields[str(f.id)] = forms.BooleanField(initial=False)    

    def get_selected(self):
        """returns selected users"""
        return filter(lambda u: self.fields[str(u.id)], self.custom_fields)

在我的模板中,我在表格中列出了用户,我希望该表格的最后一列是那些复选框。我需要根据它们的名称一一呈现字段。 我尝试创建一个模板标签,该标签将返回所需表单元素的 html 代码:

#in templatetags/user_list_tags.py
from django import template
register = template.Library()

#this is django template tag for user selection form
@register.filter 
def user_select_field(form, userid):
    """
    returns UserSelectionForm field for a user with userid
    """
    key = std(userid)
    if key not in form.fields.keys():
        print 'Key %s not found in dict' % key
        return None
        return form.fields[key].widget.render(form, key)

最后,模板代码如下:

<form action="" method="post">
{% csrf_token %}
<table class="listtable">
    <tr>
    <th>Username</th>
    <th>Select</th>
    </tr>
{% for u in userlist %}
    <tr>
    <td>{{u.username}}</td>
    <td>{{select_form|user_select_field:u.id}}</td>
    </tr>
{% endfor %}
</table>
<p><input type="submit" value="make actions" /></p>

但是,这不会将这些小部件绑定到表单,因此,在提交表单后,验证会失败。错误消息说所有自定义字段都是必需的。 所以这是我的问题:

  1. 渲染单独的表单域的正确方法是什么?

  2. 创建这种带有复选框的表单的正确方法是什么? (我的意思是也许我的方法很愚蠢,有一种更简单的方法可以实现我想要的。

【问题讨论】:

  • 也许你应该尝试用一点 javascript 来做这个。
  • 我不想在这个阶段的项目中使用 javascript。但是,我究竟应该怎么做?或者我应该谷歌什么?你知道我不是一个巨大的 javascript pro=)

标签: python django django-forms django-templates django-template-filters


【解决方案1】:

您使模板过于复杂。在表单的__init__ 方法中创建每个字段时为每个字段添加标签。

for f in userlist:
    self.fields[str(f.id)] = forms.BooleanField(label=f.username, initial=False)

然后只需遍历表单中的字段,就不用担心userlist了。

{% for field in form %}
<tr>
    <td>{{ field.label_tag }}</td>
    <td>{{ field }}</td>
</tr>
{% endfor %}

【讨论】:

  • 很遗憾,我做不到。我稍微简化了代码以使示例更清晰。在我的版本表中,带有此复选框的行有两列以上,并且除了复选框之外还有另一个小部件(“选择方法”,我可以在其中选择天气来选择所有用户,或者仅通过复选框选择)。也许我应该尝试将所有这些拆分成单独的形式?它将松散对表单get_selected 方法的封装,但可能会简化任务。?
【解决方案2】:

好的,所以我想我找到了一种正确呈现单独表单字段的方法。我发现它正在观看 django 资源。 Django.forms.forms.BaseForm 类具有 _html_output 方法,该方法创建 Django.forms.forms.BoundField 的实例,然后将 unicode(boundField) 添加到 html 输出。我做了完全相同的事情并且效果很好:

#in templatetags/user_list_tags.py
from django import template
from django import forms
register = template.Library()

#this is djangp template tag for user selection form
@register.filter
def user_select_field(form, userid):
    """
    returns UserSelectionForm field for a user with userid
    """
    key = str(userid)
    if key not in form.fields.keys():
        print 'Key %s not found in dict' % key
        return None
    #here i use BoundField:
    boundField = forms.forms.BoundField(form, form.fields[key], key)
    return unicode(boundField)

生成的 html 与 {{form.as_p}} 相同,因此 POST 请求看起来完全一样,并且会正确处理表单。

我还修复了表单类中的一些错误:

#in UserSelectionForm definition:
...
#__init__
for f in userlist:
    self.fields[str(f.id)] = forms.BooleanField(initial=False, required=False) 
#get_selected    
return filter(lambda u: self.cleaned_data[str(u.id)],
    self.custom_fields)

现在似乎可以按我的计划工作,没有任何 javascript。

【讨论】:

  • 阅读source code我发现使用form[key]而不是使用BoundField更干净,并且您会得到相同的BoundField。
猜你喜欢
  • 2019-02-23
  • 2011-05-06
  • 2021-12-15
  • 2016-12-04
  • 2020-02-05
  • 2017-05-10
  • 2015-11-27
  • 1970-01-01
  • 2016-12-06
相关资源
最近更新 更多