Django Forms에서 CSS 클래스 정의


192

내가 양식을 가지고 있다고 가정

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

렌더링 된 페이지의 클래스를 기반으로 jQuery를 사용할 수 있도록 각 필드에 CSS 클래스를 정의하는 방법이 있습니까?

양식을 수동으로 만들지 않기를 바랐습니다.



10
@skyl 장고 문서에서 찾기가 쉽지 않다는 표시로 사용하겠습니다. 탐색하고 여러 Google 검색을했는데이를 찾을 수 없으므로 질문에 대해 기뻐하며 의견을 얻습니다.
Nils

나는 그것이 오래된 스레드라는 것을 알고 있지만 장고 양식 필드에는 이제 id_fieldname 클래스가 있습니다.
ratsimihah

1
기존 필드 클래스를 고려하면서 템플릿 내의 양식 필드에 대한 클래스를 정의하는 방법에 대한 이 답변 을 참조하십시오.
dimyG

답변:


182

파이썬 코드의 변경이 필요하지 않은 또 다른 솔루션은 디자이너와 일회성 프레젠테이션 변경에 더 좋습니다 : django-widget-tweaks . 누군가 유용하게 사용되기를 바랍니다.


61
제정신 의 유일한 해결책입니다. 감사합니다!. 파이썬 코드, 특히 폼 정의에서 스타일링을위한 마지막 장소는 템플릿에 속합니다.
보리스 체 르벤 코프

5
이것은 훌륭한 도서관입니다! 이 답변이 바닥에 묻힌 것은 부끄러운 일입니다.
Chris Lacasse

1
디자이너에게 좋습니다! :-)
hobbes3

1
우수한! 이러한 작업을 수행하기 위해 일부 필터를 개발했지만이 프로젝트는 훨씬 강력합니다. 감사!
msbrogli

1
실제로 Jinja2에서도 작동합니다 :-) 안전한 파일러의 순서를 변경하고 콜론 {{myform.email | add_class ( "css_class_1 css_class_2") | safe}} 대신 괄호를 추가했습니다. 장고의 일부 여야합니다.
David Dehghan

92

내 자신의 질문에 대답했습니다. 한숨

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

위젯 생성자로 전달되었음을 알지 못했습니다.


2
ModelForm 클래스와 함께 사용할 수 없다는 것을 의미합니까?
xster

2
아니오, 위젯을 정의 할 수 있도록 모델 양식에서 양식 필드를 명시 적으로 정의하면됩니다. 또는 아래 나열된 솔루션을 사용하여 양식 필드를 다룰 필요가 없습니다.
Tom

78

다음은 클래스의 필드를 선언 한 후 위젯에 클래스 정의를 추가하는 또 다른 솔루션입니다.

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

4
ModelForms의 경우, 사용중인 기본 양식 필드를 알 필요가 없기 때문에 더 나은 경우가 있으며 런타임 조건에 따라 다른 클래스를 동적으로 설정할 수 있습니다. 메타 코딩 해킹보다 더 깨끗한 ...
Daniel Naab

1
그것은 당신이 폼의 모든 필드에 대한 입력을 원한다고 가정합니다. 양식은 반드시 모델에 연결될 필요는 없습니다. 많은 모델에 연결될 수도 있습니다. 모델 필드와 양식 필드가 1 : 1 관계인 경우에는 ModelForm이 훨씬 더 나은 선택입니다.
ashchristopher

44

사용 장고 - 위젯 개조하면 되겠 는 사용하기 쉽고 매우 잘 작동합니다.

그렇지 않으면 사용자 지정 템플릿 필터를 사용하여이 작업을 수행 할 수 있습니다.

다음과 같이 양식을 렌더링하는 것을 고려하십시오.

<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

1
그러나 이제는 한 가지 단점을 발견했습니다. 위젯 attrs에서 클래스를 정의하면이 'addcss'필터에 의해 재정의됩니다. 병합 방법에 대한 아이디어가 있습니까?
alekwisnia

1
as_widget ()은 attrs를 재정의합니다. 기존 속성을 사용하고 새로운 속성으로 확장하는 방법은 무엇입니까?
alekwisnia

기존 필드 클래스를 존중하는 방법에 대한 이 답변 을 참조하십시오
dimyG

get('class', None).split(' ')태그 에 class 속성 이 없으면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 에서 엉망이 되거나 뷰에서 수행하는 대신 ).
다윈 생존자

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'

5

당신은 이것을 시도 할 수 있습니다 ..

class SampleClass(forms.Form):
  name = forms.CharField(max_length=30)
  name.widget.attrs.update({'class': 'your-class'})
...

자세한 내용은 다음을 참조하십시오 : Django Widgets


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

제안 해 주셔서 감사합니다. 나는 더 "pythonic"접근법에 따라 대답을 편집했습니다.
Charlesthk

위대한!, 내가 무엇을 찾고 있었다입니다
우갈리 소프트

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.