37

これに似た Django フォーム クラスを定義すると、次のようになります。

def class MyForm(forms.Form):
    check = forms.BooleanField(required=True, label="Check this")

次のような HTML に展開されます。

<form action="." id="form" method=POST>
<p><label for="check">Check this:</label> <input type="checkbox" name="check" id="check" /></p>
<p><input type=submit value="Submit"></p>
</form>

チェックボックスの入力要素に、チェックボックスに続くラベルを付けたいのですが、その逆ではありません。Djangoにそうするよう説得する方法はありますか?

[編集]

Jonas からの回答に感謝します - それでも、私が尋ねた問題 (チェックボックスのラベルがチェックボックスの右側にレンダリングされる) は修正されますが、新しい問題が発生します (すべてのウィジェットのラベルはウィジェットの右側にレンダリングされます...)

_html_output() は明らかに設計されていないため、オーバーライドを避けたいと思います。私が思いついた設計は、Field クラスにフィールド html 出力メソッドを実装し、Boolean フィールドのメソッドをオーバーライドし、そのメソッドを _html_output() で使用することです。残念なことに、Django 開発者は別の道を選んだので、私は可能な限り既存のフレームワーク内で作業したいと考えています。

CSS はまともなアプローチのように思えますが、これを実行するのに十分な CSS を知らないか、このアプローチが好きかどうかを判断することさえできません。さらに、少なくともレンダリングの順序で、最終出力に似たマークアップを好みます。

さらに、特定のマークアップに対して複数のスタイル シートを使用することは合理的である可能性があるため、CSS でこれを行うと、複数のスタイルに対して複数回行う必要が生じる可能性があり、CSS はほとんど間違った答えになります。

[編集]

以下の自分の質問に答えているようです。誰かがこれを行う方法をよりよく知っている場合は、恥ずかしがらないでください。

4

7 に答える 7

33

これが私が思いついた解決策です(Django v1.1):

{% load myfilters %}

[...]

{% for field in form %}
    [...]
    {% if field.field.widget|is_checkbox %}
      {{ field }}{{ field.label_tag }}
    {% else %}
      {{ field.label_tag }}{{ field }}
    {% endif %}
    [...]
{% endfor %}

次のようなものを含むカスタムテンプレートタグ(この例では「myfilters.py」ファイル)を作成する必要があります。

from django import template
from django.forms.fields import CheckboxInput

register = template.Library()

@register.filter(name='is_checkbox')
def is_checkbox(value):
    return isinstance(value, CheckboxInput)

カスタムテンプレートタグの詳細については、こちらをご覧ください

編集:アスカー自身の答えの精神で:

利点:

  1. CSSをいじくりまわすことはありません。
  2. マークアップは、想定どおりに表示されることになります。
  3. Djangoの内部をハックしませんでした。(しかし、かなりの束を見なければなりませんでした)
  4. テンプレートは素晴らしく、コンパクトで慣用的です。
  5. フィルタコードは、ラベルと入力フィールド名の正確な値に関係なく適切に機能します。

短所:

  1. おそらくどこかにそれをより良くそしてより速くする何かがあるでしょう。
  2. ラベルを右に移動するためだけに、クライアントがこれに費やしたすべての時間を喜んで支払うことはありそうにありません...
于 2010-01-11T22:06:27.673 に答える
15

私は romkyns からの回答を取得し、もう少し一般的なものにしました

def field_type(field, ftype):
    try:
        t = field.field.widget.__class__.__name__
        return t.lower() == ftype
    except:
        pass
    return False

このようにして、ウィジェットのタイプを文字列で直接確認できます

{% if field|field_type:'checkboxinput' %}
    <label>{{ field }} {{ field.label }}</label>
{% else %}
    <label> {{ field.label }} </label> {{ field }}
{% endif %}
于 2010-02-22T03:52:58.357 に答える
12

提示されたすべてのソリューションにはテンプレートの変更が含まれますが、これは一般にパフォーマンスに関してはかなり非効率的です。これを行うカスタム ウィジェットを次に示します。

from django import forms
from django.forms.fields import BooleanField
from django.forms.util import flatatt
from django.utils.encoding import force_text
from django.utils.html import format_html
from django.utils.translation import ugettext as _


class PrettyCheckboxWidget(forms.widgets.CheckboxInput):
    def render(self, name, value, attrs=None):
        final_attrs = self.build_attrs(attrs, type='checkbox', name=name)
        if self.check_test(value):
            final_attrs['checked'] = 'checked'
        if not (value is True or value is False or value is None or value == ''):
            final_attrs['value'] = force_text(value)
        if 'prettycheckbox-label' in final_attrs:
            label = _(final_attrs.pop('prettycheckbox-label'))
        else:
            label = ''
        return format_html('<label for="{0}"><input{1} /> {2}</label>', attrs['id'], flatatt(final_attrs), label)


class PrettyCheckboxField(BooleanField):
    widget = PrettyCheckboxWidget
    def __init__(self, *args, **kwargs):
        if kwargs['label']:
            kwargs['widget'].attrs['prettycheckbox-label'] = kwargs['label']
            kwargs['label'] = ''
        super(PrettyCheckboxField, self).__init__(*args, **kwargs)


# usage in form
class MyForm(forms.Form):
    my_boolean = PrettyCheckboxField(label=_('Some label'), widget=PrettyCheckboxWidget())

追加のファイルに PrettyCheckboxWidget と PrettyCheckboxField があるので、必要に応じてインポートできます翻訳が必要ない場合は、ugettext 部分を削除できます。このコードはDjango 1.5で動作し、それ以前のバージョンではテストされていません。

利点:

  • 高性能で、テンプレートの変更は不要
  • カスタムウィジェットとして使いやすい

短所:

  • 「as_table」は、2 番目の列内にチェックボックス + ラベルをレンダリングします
  • テンプレート内の {{ field.label }} は空です。代わりに、ラベルは {{ フィールド }} にバインドされます
  • 土曜日に予定していたよりも多くの作業が行われました ;-)
于 2013-03-09T07:18:55.620 に答える
3

ユーザーが CSS を除外したことは知っていますが、上位の回答がこのような小さなことを行うのに約 30 分かかることを考えると、Web サイトではこのような詳細が重要であることを知っているので、CSS ソリューションに落ち着きます.

チェックボックス.css

input[type="checkbox"] {
    float: left;
    margin-right: 10px;
    margin-top: 4px;
}

フォーム.py

class MyForm(forms.ModelForm):
    # ...
    class Media:
    css = {
        'all': 'checkbox.css',
    }

template.html

{{ form.media }}
{{ form.as_p }}

利点:

  • 速い!
  • テンプレートタグとの混乱はありません(ただform.as_p
  • 新しいいまいましいウィジェットはありません
  • CSS ファイルはすべてのフォームに自動的に含まれます

短所:

  • HTML はプレゼンテーションを反映していません (しかし、十分です!)
  • あなたのフロントエンドは不平を言うかもしれません
于 2013-07-23T11:27:15.230 に答える
2

Django admin でチェックボックスの位置を変更するのは非常に難しい場合がありますが、幸いなことに、カスタム ウィジェットを使用した簡単な解決策があります。

from django.forms.widgets import Widget, CheckboxInput, boolean_check

class RightCheckbox(Widget):
    render = CheckboxInput().render

    def __init__(self, attrs=None, check_test=None):
        super(RightCheckbox, self).__init__(attrs)
        self.check_test = boolean_check if check_test is None else check_test

Django は、ウィジェットがサブクラスの場合にのみ左位置を使用しますCheckboxInput

于 2015-02-15T19:11:24.823 に答える
2

これが私がやったことです。タグを切り替えるカスタム テンプレート stringfilter を作成しました。今、私のテンプレートコードは次のようになります:

{% load pretty_forms %}
<form action="." method="POST">
{{ form.as_p|pretty_checkbox }}
<p><input type="submit" value="Submit"></p>
</form>

プレーンな Django テンプレートとの唯一の違いは、{% load %} テンプレート タグとpretty_checkboxフィルターの追加です。

以下は、 pretty_checkboxの機能的だが醜い実装です。このコードにはエラー処理がありません。Django によって生成された属性が非常に特殊な方法でフォーマットされていることを前提としているため、コードで次のようなものを使用することはお勧めできません。

from django import template
from django.template.defaultfilters import stringfilter
import logging

register=template.Library()

@register.filter(name='pretty_checkbox')
@stringfilter
def pretty_checkbox(value):
    # Iterate over the HTML fragment, extract <label> and <input> tags, and
    # switch the order of the pairs where the input type is "checkbox".
    scratch = value
    output = ''
    try:
        while True:
            ls = scratch.find('<label')
            if ls > -1:
                le = scratch.find('</label>')
                ins = scratch.find('<input')
                ine = scratch.find('/>', ins)
                # Check whether we're dealing with a checkbox:
                if scratch[ins:ine+2].find(' type="checkbox" ')>-1:
                    # Switch the tags
                    output += scratch[:ls]
                    output += scratch[ins:ine+2]
                    output += scratch[ls:le-1]+scratch[le:le+8]
                else:
                    output += scratch[:ine+2]
                scratch = scratch[ine+2:]
            else:
                output += scratch
                break
    except:
        logging.error("pretty_checkbox caught an exception")
    return output

pretty_checkboxはその文字列引数をスキャンし、<label> タグと <input> タグのペアを見つけて、<input> タグのタイプが「checkbox」の場合はそれらを切り替えます。また、ラベルの最後の文字である「:」文字も削除されます。

利点:

  1. CSS で混乱することはありません。
  2. マークアップは、想定どおりに表示されます。
  3. 私は Django の内部をハックしていません。
  4. テンプレートは素晴らしく、コンパクトで慣用的です。

短所:

  1. フィルター コードは、ラベルと入力フィールド名のエキサイティングな値についてテストする必要があります。
  2. それをより良く、より速く行う何かがおそらくどこかにあるでしょう。
  3. 土曜日に予定していたよりも多くの仕事。
于 2009-02-22T06:25:08.273 に答える
1

入力とラベルの順序は、フォームのnormal_rowパラメーターを介して提供され、チェックボックスに異なる行パターンはありません。したがって、これを行うには2つの方法があります(0.96バージョンでは正確に):
1。フォームの_html_outputをオーバーライドします2.CSSを
使用してラベルとチェックボックスの位置を変更します

于 2009-02-21T06:52:58.230 に答える