djangoフォームでCSSクラスを定義する


192

フォームがあると仮定します

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

レンダリングされたページのクラスに基づいてjQueryを使用できるように、各フィールドにcssクラスを定義する方法はありますか?

フォームを手動で作成する必要がないことを望んでいました。


9
うわー、みんな投票してる?docs.djangoproject.com/en/dev/ref/forms/widgets/...
Skylar Saveland

10
@skyl私はそれをdjango docsで見つけるのが簡単ではないことを示していると思います。私もブラウジングしていくつかのグーグル検索を行ったが、これを見つけることができなかったので、私は質問を嬉しく思い、それが私の賛成票を獲得する。
ニルス

私はそれが古いスレッドであることを知っていますが、Djangoのフォームフィールドにはid_fieldnameクラスがあります。
ratimihah 2013

1
既存のフィールドクラスを尊重しながらテンプレート内のフォームフィールドのクラスを定義する方法については、この回答を参照してください
dimyG

回答:


182

Pythonコードの変更を必要としないさらに別のソリューションは、デザイナーや1回限りのプレゼンテーションの変更に適しています。 django-widget-tweaks。誰かがそれが役に立つことを願っています。


61
唯一まともな解決策は、私が言わなければなりません。ありがとうございました!。Pythonコード、特にフォームの定義では、スタイリングのための要素を配置する最後の場所です-これらは間違いなくテンプレートに属します。
Boris Chervenkov

5
これは素晴らしいライブラリです!この答えが底に埋もれているのは残念です。
Chris Lacasse、2012年

1
デザイナーに最適!:-)
hobbes3

1
優れた!これらのことを行うためにいくつかのフィルターを開発しましたが、このプロジェクトははるかに強力です。ありがとう!
msbrogli

1
実際にはJinja2でも機能します:-)安全なファイターの順序を変更し、コロンの代わりに括弧を追加しました{{myform.email | add_class( "css_class_1 css_class_2")| safe}}これを書いてくれてありがとう。Djangoの一部である必要があります。
David Dehghan 2013

92

私自身の質問に答えました。はぁ

http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs

ウィジェットコンストラクターに渡されていることに気付きませんでした。


2
それはModelFormクラスで使用できないことを意味しますか?
xster

2
いいえ、ウィジェットを定義できるように、モデルフォームでフォームフィールドを明示的に定義する必要があるだけです。または、以下にリストされている解決策を使用して、フォームフィールドを変更する必要がないようにします。
トム

78

これは、クラスのフィールドを宣言した後にウィジェットにクラス定義を追加するための別のソリューションです。

def __init__(self, *args, **kwargs):
    super(SampleClass, self).__init__(*args, **kwargs)
    self.fields['name'].widget.attrs['class'] = 'my_class'

4
ModelFormsの場合、使用されているデフォルトのフォームフィールドを意識する必要がなく、実行時の条件に基づいてさまざまなクラスを動的に設定できるため、これは多くの場合より優れています。メタコーディングハックよりもクリーン...
Daniel Naab 2008

1
これは、フォームのすべてのフィールドに入力が必要であることを前提としていますが、多くの場合そうではありません。フォームは必ずしもモデルに関連付けられているわけではありません。多くのモデルに関連付けられている場合があります。モデルフィールドとフォームフィールドが1:1の関係にある場合、はい、ModelFormの方がはるかに適切です。
ashchristopher 2008

44

django-widget-tweaksを使用してください。使いやすく、非常にうまく機能します。

それ以外の場合は、カスタムテンプレートフィルターを使用して行うことができます。

このようにフォームをレンダリングするとすると、

<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject }}
    </div>
</form>

form.subjectは、as_widgetメソッドを持つBoundFieldのインスタンスです。

「my_app / templatetags / myfilters.py」にカスタムフィルター「addcss」を作成できます

from django import template

register = template.Library()

@register.filter(name='addcss')
def addcss(value, arg):
    css_classes = value.field.widget.attrs.get('class', '').split(' ')
    if css_classes and arg not in css_classes:
        css_classes = '%s %s' % (css_classes, arg)
    return value.as_widget(attrs={'class': css_classes})

次に、フィルターを適用します。

{% load myfilters %}
<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject|addcss:'MyClass' }}
    </div>
</form>

その後、form.subjectsは "MyClass" cssクラスでレンダリングされます。

この助けを願っています。

編集1

  • dimyGの回答に従ってフィルターを更新する

  • django-widget-tweakリンクを追加

編集2

  • Bhydのコメントに従ってフィルタを更新

3
これは素晴らしい!これはDRYであり、ディスプレイレイヤーをコントロールレイヤーから分離します。私からの+1!
alekwisnia 2013年

1
しかし、今、私は1つの欠点に気づきました。ウィジェット属性でクラスを定義すると、この「addcss」フィルターによってオーバーライドされます。それをマージする方法について何かアイデアはありますか?
アレクウィスニア2013年

1
つまり、as_widget()はattrsをオーバーライドします。既存の属性を確実に使用し、新しい属性で拡張する方法は?
アレクウィスニア2013年

既存のフィールドクラスを尊重する方法については、この回答を参照してください
dimyG 2016

get('class', None).split(' ')返されるように、タグにクラス属性がない場合は失敗しますNone。それを変更するget('class', '').split(' ')作品
dtasev

32

docs.djangoproject.comで指定されたメソッドを展開します。

class MyForm(forms.Form): 
    comment = forms.CharField(
            widget=forms.TextInput(attrs={'size':'40'}))

すべてのフィールドのネイティブウィジェットタイプを知る必要があるのは面倒だと思い、フォームフィールドにクラス名を置くだけでデフォルトをオーバーライドするのはおかしいと思いました。これは私にとってはうまくいくようです:

class MyForm(forms.Form): 
    #This instantiates the field w/ the default widget
    comment = forms.CharField()

    #We only override the part we care about
    comment.widget.attrs['size'] = '40'

これは私には少しきれいに思えます。


これは、要求された「クラス」ではなく「サイズ」で実行していることを除いて、他の人が何年も前に言ったこととまったく同じです。
Chris Morgan

3
@Chris Morgan実際、彼はフォーム宣言自体で「comment.widget.attrs」を使用することを提案した最初の人です(initをいじったり、ビューで実行したりする代わりに)。
DarwinSurvivor

29

フォームのすべてのフィールドに特定のクラスを継承させる場合は、から継承する親クラスを定義し、forms.ModelFormそれから継承するだけです

class BaseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args, **kwargs)
        for field_name, field in self.fields.items():
            field.widget.attrs['class'] = 'someClass'


class WhateverForm(BaseForm):
    class Meta:
        model = SomeModel

これ'form-control'により、コードのレプリケーションを追加することなく、アプリケーションのすべてのフォームのすべてのフィールドにクラスを自動的に追加できました。


1
クラス名は大文字で始めてください(BaseFormの方がはるかに優れているようです)
Alvaro

16

これは、ビューを変更する簡単な方法です。テンプレートに渡す直前にビューの下に追加します。

form = MyForm(instance = instance.obj)
form.fields['email'].widget.attrs = {'class':'here_class_name'}

14

次のように、フォームにクラスを追加するだけです。

class UserLoginForm(forms.Form):
    username = forms.CharField(widget=forms.TextInput(
        attrs={
        'class':'form-control',
        'placeholder':'Username'
        }
    ))
    password = forms.CharField(widget=forms.PasswordInput(
        attrs={
        'class':'form-control',
        'placeholder':'Password'
        }
    ))

5

これは、すべてのフィールドに同じクラスを与える上記のバリエーションです(たとえば、jqueryの角の丸い素敵なもの)。

  # Simple way to assign css class to every field
  def __init__(self, *args, **kwargs):
    super(TranslatedPageForm, self).__init__(*args, **kwargs)
    for myField in self.fields:
      self.fields[myField].widget.attrs['class'] = 'ui-state-default ui-corner-all'


2

テンプレートのフォームのフィールド(view.pyやform.pyではなく)にクラスを追加する場合、たとえば、ビューを上書きせずにサードパーティのアプリを変更する場合は、テンプレートのフィルターを説明どおりに使用します。中Charlesthkの 答え非常に便利です。しかし、この回答では、テンプレートフィルターはフィールドが持つ可能性のある既存のクラスをオーバーライドします。

これを編集として追加しようとしましたが、新しい回答として書くよう提案されました。

それで、これはフィールドの既存のクラスを尊重するテンプレートタグです:

from django import template

register = template.Library()


@register.filter(name='addclass')
def addclass(field, given_class):
    existing_classes = field.field.widget.attrs.get('class', None)
    if existing_classes:
        if existing_classes.find(given_class) == -1:
            # if the given class doesn't exist in the existing classes
            classes = existing_classes + ' ' + given_class
        else:
            classes = existing_classes
    else:
        classes = given_class
    return field.as_widget(attrs={"class": classes})

あなたの提案をありがとう。私はそれに応じて、より「パイソン的な」アプローチで私の回答を編集しました。
Charlesthk

great !!、それが私が探していたものです
ugali soft

1

結局のところ、これはフォームコンストラクター(init関数)で、またはフォームクラスが開始された後に実行できます。これは、独自のフォームを作成しておらず、そのフォームが他の場所から来ている場合に必要になることがあります-

def some_view(request):
    add_css_to_fields = ['list','of','fields']
    if request.method == 'POST':
        form = SomeForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/thanks/')
    else:
        form = SomeForm()

    for key in form.fields.keys():
        if key in add_css_to_fields:
            field = form.fields[key]
            css_addition = 'css_addition '
            css = field.widget.attrs.get('class', '')
            field.widget.attrs['class'] = css_addition + css_classes

    return render(request, 'template_name.html', {'form': form})

1

Django Crispy Formsを使用することもできます。これは、BootstrapやFoundationなどのCSSフレームワークを使用したい場合にフォームを定義するための優れたツールです。フォームフィールドのクラスを指定するのは簡単です。

あなたのフォームクラスはこのようになります:

from django import forms

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Submit, Field
from crispy_forms.bootstrap import FormActions

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

    helper = FormHelper()
    helper.form_class = 'your-form-class'
    helper.layout = Layout(
        Field('name', css_class='name-class'),
        Field('age', css_class='age-class'),
        Field('django_hacker', css-class='hacker-class'),
        FormActions(
            Submit('save_changes', 'Save changes'),
        )
    )
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.