如何在模板中渲染django表单字段

Vic*_*oon 12 python django django-templates django-forms django-template-filters

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

#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)
Run Code Online (Sandbox Code Playgroud)

在我的模板中,我在表中列出了用户,我希望此表的最后一列是那些复选框.我需要根据名称逐个渲染字段.我尝试创建一个模板标签,它将返回所需表单元素的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)
Run Code Online (Sandbox Code Playgroud)

最后,这是模板代码:

<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>
Run Code Online (Sandbox Code Playgroud)

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

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

  2. 使用复选框创建此类表单的正确方法是什么?(我的意思是,我的方法可能很愚蠢,有一种更容易实现我想要的方法.

Chr*_*att 13

你让模板太复杂了.在表单的__init__方法中创建标签时,为每个字段添加标签.

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

然后只是循环遍历表单中的字段,不再担心userlist了.

{% for field in form %}
<tr>
    <td>{{ field.label_tag }}</td>
    <td>{{ field }}</td>
</tr>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)


Vic*_*oon 8

好吧我想我已经找到了一种正确渲染单独表单字段的方法.我发现它看着django的来源.Django.forms.forms.BaseFormclass具有_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)
Run Code Online (Sandbox Code Playgroud)

这生成了与{{form.as_p}}相同的html,因此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)
Run Code Online (Sandbox Code Playgroud)

现在似乎按照我的计划工作,没有任何JavaScript.

  • 阅读[源代码](https://github.com/django/django/blob/master/django/forms/forms.py#L108)我发现不是使用BoundField,而是使用`form [key] `你得到的是相同的BoundField. (3认同)