web-dev-qa-db-ja.com

テンプレートのDjangoフォームフィールドをレンダリングする方法

ユーザーのリストと、ユーザーが選択されているかどうかを通知するチェックボックスを含むページを作成します。これにより、選択されたユーザーに何らかのアクションが適用されます。次のようなフォームクラスを作成しました。

#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)

私のテンプレートでは、ユーザーがテーブルにリストされており、このテーブルの最後の列をそれらのチェックボックスにします。名前に応じて、フィールドを1つずつレンダリングする必要があります。必要なフォーム要素の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. チェックボックスを使用してこのようなフォームを作成する正しい方法は何ですか? (多分私の方法は愚かであり、私が望むものを達成するためのはるかに簡単な方法があります。

12
Victor Proon

さて、私は別々のフォームフィールドを正しくレンダリングする方法を見つけたと思います。 Djangoソース。_Django.forms.forms.BaseForm_クラスには__html_output_のインスタンスを作成し、unicode(boundField)を追加する_Django.forms.forms.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)
_

これにより、{{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)
_

これは、JavaScriptがなくても、計画どおりに機能しているようです。

8
Victor Proon

テンプレートを複雑にしすぎています。フォームの__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 %}
13
Chris Pratt