Визначте клас css у формах django


192

Припустимо, у мене є форма

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

Чи є спосіб для мене визначити класи css для кожного поля таким чином, щоб потім я міг використовувати jQuery на основі класу на моїй наданій сторінці?

Я сподівався, що не доведеться вручну формувати форму.


9
вау, всі голосують за це? docs.djangoproject.com/en/dev/ref/forms/widgets/…
— Skylar Saveland

10
@skyl Я б вважав це свідченням того, що знайти його в документах про джанго непросто. Я також переглянув і здійснив кілька пошукових запитів google, і не зміг його знайти, тому радий за запитання, і це отримало мою нагоду.
— Нільс

Я знаю, що це стара нитка, але в полях форми Django тепер є клас id_fieldname.
— ratsimihah

1
Дивіться цю відповідь про те, як визначити класи для поля форми всередині шаблону, дотримуючись існуючих класів поля
— dimyG

Відповіді:


182

Ще одне рішення, яке не потребує змін у коді python, і так краще для дизайнерів та разових презентаційних змін: django-widget-tweaks . Сподіваюся, хтось вважатиме це корисним.


61
Тільки осудна рішення, я повинен сказати. Дякую!. Код Python, особливо у визначенні форми, є останнім місцем для розміщення матеріалів для стилізації - вони, безумовно, належать до шаблонів.
— Борис Червенков

5
Це чудова бібліотека! Соромно, що ця відповідь похована внизу.
— Кріс Лакасс

1
Чудово підходить для дизайнерів! :-)
— hobbes3

1
Відмінно! Я розробив кілька фільтрів, щоб зробити ці речі, але цей проект набагато потужніший. Дякую!
— msbrogli

1
насправді це працює для Jinja2 також :-) Я змінив порядок безпечного файлера і додав дужки замість двокрапки {{myform.email | add_class ("css_class_1 css_class_2") | безпечний}} дякую за написання цього. він повинен бути частиною Джанго.
— Девід Дехган,

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 це часто краще, оскільки вам не потрібно знати про використовуване поле форми за замовчуванням, і ви можете динамічно встановлювати різні класи на основі умов виконання. Чистіше, ніж мета-кодування хаків ...
— Даніель Нааб

1
Це передбачає, що ви хочете ввести для кожного поля форму, що часто не так. Форма не обов'язково прив'язується до моделі - вона може бути прив’язана до багатьох моделей. У випадку, якщо в модельних полях та полях форм є співвідношення 1: 1, то так, ModelForm є набагато кращим вибором.
— ашхрістофер

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 - це екземпляр BoundField, який має метод as_widget .

ви можете створити спеціальний фільтр "addcss" у "my_app / templatetags / myfilters.py"

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 буде надано з класом css "MyClass".

Сподіваюся, що це допоможе.

ЗРІД 1

  • Оновлення фільтра в відповідно до dimyG відповідь «пд.ш.

  • Додати посилання django-widget-tweak

EDIT 2

  • Оновіть фільтр відповідно до коментаря Bhyd

3
Це чудово! Це DRY, і він відокремлює дисплейний шар від керуючого шару. +1 від мене!
— alekwisnia

1
Однак зараз я помітив один недолік. Якщо я визначаю клас у attrs віджетів, то їх переосмислює цей фільтр 'addcss'. Чи є у вас ідеї, як це злити?
— alekwisnia

1
Я маю на увазі, як as_widget () переосмислює attrs. Як переконатися, що він використовує існуючі attrs та розширює їх новими?
— alekwisnia

Дивіться цю відповідь про те, як поважати існуючі класи на місцях
— dimyG

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'

Це здається мені трохи чистішим.


Це саме те, що говорили інші століття тому, за винятком того, що ви робите це з "розміром", а не "класом", про який вимагали.
— Кріс Морган

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 здається набагато кращою назвою для цього)
— Альваро

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

Дякуємо за вашу пропозицію. Відповідно я відредагував свою відповідь більш "пітонічним" підходом.
— Шарлестк

чудово !!, це те, що я шукав
— 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 , це чудовий інструмент для визначення форм на випадок, якщо ви хочете використовувати такі рамки CSS, як Bootstrap або Foundation. І там легко вказати класи для ваших полів форми.

Ваш клас класів хотів би цього:

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'),
        )
    )
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.