Визначте клас 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.