CSS-стиль у формах Джанго


150

Я хотів би стилізувати наступне:

form.py:

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    email = forms.EmailField(required=False)
    message = forms.CharField(widget=forms.Textarea)

contact_form.html:

<form action="" method="post">
  <table>
    {{ form.as_table }}
  </table>
  <input type="submit" value="Submit">
</form>

Наприклад, як я поставив клас або ID для subject, email, messageщоб забезпечити зовнішню таблицю стилів?

Відповіді:


192

Взяте з моєї відповіді на: Як розмітити поля форми з <div class = 'field_type'> у Django

class MyForm(forms.Form):
    myfield = forms.CharField(widget=forms.TextInput(attrs={'class' : 'myfieldclass'}))

або

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['myfield'].widget.attrs.update({'class' : 'myfieldclass'})

або

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'myfield': forms.TextInput(attrs={'class': 'myfieldclass'}),
        }

--- EDIT ---
Вищенаведене найпростіше змінити оригінальний код запитання, який виконує запитання. Це також утримує вас від повторення, якщо ви повторно використовуєте форму в інших місцях; ваші класи або інші атрибути просто працюють, якщо ви використовуєте методи форми Django as_table / as_ul / as_p. Якщо вам потрібен повний контроль для повністю користувальницької візуалізації, це чітко зафіксовано

- EDIT 2 ---
Додано новіший спосіб вказати віджет та attrs для ModelForm.


27
Хоча не рекомендується поєднувати презентацію з діловою логікою.
Торстен Енгельбрехт

8
Як ця презентація? Ви даєте елементу клас, який є лише ідентифікатором чи категоризацією. Ви все ще повинні визначити, що це робить в іншому місці
shadfc

9
Так і ні. Перші класи CSS звичайно використовуються для стилізації, якщо вам потрібен унікальний ідентифікатор, який краще використовувати id. По-друге, це зазвичай відповідальність шаблону, щоб це зробити детальніше, особливо якщо ви збираєтесь отримати доступ до цього класу методами frontend (js, css). Я не сказав, що ваша відповідь неправильна. На мою думку, це лише погана практика (особливо, коли ти працюєш у команді з розробниками інтернету та бекенда).
Торстен Енгельбрехт

6
Це виглядає смішно, просто для додання класу вам потрібен стільки код? Здається, було б простіше просто зашифрувати HTML / CSS у цих областях (особливо для CSS-важкого сайту).
David542

9
Це божевільне джанго робить це таким незручним!
Брайс

103

Це можна зробити за допомогою спеціального фільтра шаблонів. Подумайте, як надіслати форму таким чином:

<form action="/contact/" method="post">
  {{ form.non_field_errors }}
  <div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject }}
    <span class="helptext">{{ form.subject.help_text }}</span>
  </div>
</form>

form.subjectє екземпляром, BoundFieldякий має as_widget()метод.

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

from django import template

register = template.Library()

@register.filter(name='addclass')
def addclass(value, arg):
    return value.as_widget(attrs={'class': arg})

А потім застосуйте свій фільтр:

{% load myfilters %}

<form action="/contact/" method="post">
  {{ form.non_field_errors }}
  <div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject|addclass:'MyClass' }}
    <span class="helptext">{{ form.subject.help_text }}</span>
  </div>
</form>

form.subjectsпотім буде надано з MyClassкласом CSS.


5
Це одне з найбільш чистих та простих у здійсненні рішень
користувач

5
Ця відповідь повинна бути головною відповіддю !!! Це дійсно чисто, ніж запропоноване рішенням Джанго! Молодці @Charlesthk
David D.

4
Супер корисно. Спочатку мені це не було очевидно, але ви можете використовувати це, щоб додати також кілька класів:{{ form.subject|addclass:'myclass1 myclass2' }}
smg

Мені подобається, що це дозволяє зберігати класи HTML у файлах HTML. Під час роботи зі стилем я переходжу між таблицями стилів та структурою, а не моделями та / або формами.
Кевін

29

Якщо ви не хочете додати будь-який код до форми (як зазначено в коментарях до відповіді @ shadfc), це, безумовно, можливо, ось два варіанти.

По-перше, ви просто посилаєтесь на поля окремо в HTML, а не на всю форму одразу:

<form action="" method="post">
    <ul class="contactList">
        <li id="subject" class="contact">{{ form.subject }}</li>
        <li id="email" class="contact">{{ form.email }}</li>
        <li id="message" class="contact">{{ form.message }}</li>
    </ul>
    <input type="submit" value="Submit">
</form>

(Зверніть увагу, що я також змінив його на несортований список .)

По-друге, зверніть увагу на документи про виведення форм у вигляді HTML , Django:

Ідентифікатор поля, генерується, попередньо додавши 'id_' до імені поля. Атрибути і теги id за замовчуванням включені у висновок.

У всіх ваших полях форм вже є унікальний ідентифікатор . Тож ви посилаєте id_subject у своєму CSS-файлі, щоб стилізувати поле теми . Слід зазначити, що так поводиться форма, коли ви приймаєте HTML за замовчуванням , що вимагає просто друкувати форму, а не окремі поля:

<ul class="contactList">
    {{ form }}  # Will auto-generate HTML with id_subject, id_email, email_message 
    {{ form.as_ul }} # might also work, haven't tested
</ul>

Дивіться попереднє посилання щодо інших параметрів при виведенні форм (ви можете робити таблиці тощо).

Примітка. Я розумію, що це не те саме, що додавати клас до кожного елемента (якщо ви додали поле до Форми, вам також потрібно буде оновити CSS) - але досить просто посилатись на всі поля за допомогою id у вашому CSS так:

#id_subject, #id_email, #email_message 
{color: red;}

Я спробував ваше друге рішення, але це не вийшло. Я створив клас для id_email, і він не дав жодних результатів.
майже початківець

@almostabeginner одне, що я можу запропонувати для налагодження - як тільки ви побачите сторінку в браузері, використовуйте Перегляд джерела сторінки (як правило, клацанням правою кнопкою миші) та перегляньте фактичну повну сторінку, яку генерує Django. Перевірте, чи існують поля з ідентифікатором або ідентифікатором класу, який ви очікуєте. Також більшість браузерів (можливо, встановивши плагін) можуть запустити налагоджувач, який показує вам css, який застосовується до сторінки, також корисно побачити, що відбувається.
Джон С

@almostabeginner також зауважте, я додав трохи зразкового коду. У випадку, якщо це було не зрозуміло лише з тексту - вам потрібно посилатися на саму форму, а не на окремі поля, і тоді форма автоматично генерує HTML, що містить ідентифікатори , як описано. Сподіваємось, це допомагає.
Джон С

1
Дякую за допомогу, проблема зовсім не була моїм css, проблема стосувалася кеша. Отже, мій старий файл css зберігався, тому жодна із змін не відображатиметься. Я просто очистив кеш-пам'ять від хрому, і всі оновлення почали відображатися.
майже початківець

15

За цим дописом у блозі можна додавати класи css у свої поля за допомогою спеціального фільтра шаблонів.

from django import template
register = template.Library()

@register.filter(name='addcss')
def addcss(field, css):
    return field.as_widget(attrs={"class":css})

Помістіть це у теги шаблонів / папки вашого додатка, і тепер ви можете це зробити

{{field|addcss:"form-control"}}

2
це повинно було бути прийнято як справжню відповідь на цей пост :)
mvdb

Найкраще рішення на сьогоднішній день.
Моди Vs Rockers

1
Блискуче, дякую! Не забудьте фактично завантажити тег. Крім того, у Django 2.1 єдиний спосіб, як я міг змусити Django знайти шаблон, був додавши параметр у settings.py: 'бібліотеки': {'add_css': 'app.templatetags.tag_name',}
simonbogarde

11

Ви можете зробити так:

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    subject.widget.attrs.update({'id' : 'your_id'})

Сподіваюся, що це працює.

Ігнас


Спасибі ігна. Точна відповідь!
Rudresh Ajgaonkar

9

Ви можете використовувати цю бібліотеку: https://pypi.python.org/pypi/django-widget-tweaks

Це дозволяє зробити наступне:

{% load widget_tweaks %}
<!-- add 2 extra css classes to field element -->
{{ form.title|add_class:"css_class_1 css_class_2" }}

1
Погляньте на рішення Charlesthk, те саме, без додавання додаткової бібліотеки :)
Девід Д.

@DavidW .: Так, але Widget Tweaks має ще багато фільтрів, таких як render_field.
mrdaliri

5

Ви можете зробити:

<form action="" method="post">
    <table>
        {% for field in form %}
        <tr><td>{{field}}</td></tr>
        {% endfor %}
    </table>
    <input type="submit" value="Submit">
</form>

Потім ви можете додати класи / id до, наприклад, <td>тегу. Звичайно, ви можете використовувати будь-які інші теги, які хочете. Перевірте Робота з формами Django як приклад того, що доступно для кожної fieldформи ( {{field}}наприклад, просто виведення тегу введення, а не мітки тощо).


3

Одне рішення - використовувати JavaScript для додавання необхідних класів CSS після того, як сторінка буде готова. Наприклад, виведення форми django форми з класами завантаження (jQuery використовується для стислості):

<script type="text/javascript">
    $(document).ready(function() {
        $('#some_django_form_id').find("input[type='text'], select, textarea").each(function(index, element) {
            $(element).addClass("form-control");
        });
    });
</script>

Це дозволяє уникнути неподобства змішування специфіки стилізації з вашою бізнес-логікою.


3

Напишіть свою форму так:

    class MyForm(forms.Form):
         name = forms.CharField(widget=forms.TextInput(attr={'class':'name'}),label="Your Name")
         message = forms.CharField(widget=forms.Textarea(attr={'class':'message'}), label="Your Message")

У полі HTML зробіть щось на кшталт:

{% for field in form %}
      <div class="row">
        <label for="{{ field.name}}">{{ field.label}}</label>{{ field }}
     </div>
{% endfor %}

Потім у свій CSS напишіть щось на кшталт:

.name{
      /* you already have this class so create it's style form here */
}
.message{
      /* you already have this class so create it's style form here */
}
label[for='message']{
      /* style for label */
}

Сподіваюся, що цю відповідь варто спробувати! Зауважте, що ви повинні записати свої представлення, щоб відтворити файл HTML, який містить форму.


Дякую. але як я можу написати конкретний текст етикетки?
gakeko betsi

2

Можливо, вам не знадобиться переосмислювати клас форми ' __init__, оскільки Django встановлює nameта idатрибути в HTML input. Ви можете мати такий CSS:

form input[name='subject'] {
    font-size: xx-large;
}

1
Щоб додати до цього. З огляду на "предмет = форми ...", id = "id_subject" і name = "предмет" є умовою Джанго для цих атрибутів. Тому ви також повинні мати можливість #id_subject {...}
solartic

@solartic: Ти маєш рацію, дякую. Я не згадував про це, тому що idполе, створене Джанго для наборів форматів, стає досить волохатим…
tehfink

2

Не бачив цього справді ...

https://docs.djangoproject.com/en/1.8/ref/forms/api/#more-granular-output

Більш деталізований вихід

Методи as_p (), as_ul () та as_table () - це просто ярлики для ледачих розробників - вони не єдиний спосіб відображення об’єкта форми.

клас BoundField Використовується для відображення атрибутів HTML або доступу для одного поля екземпляра форми.

Метод str () ( unicode на Python 2) цього об'єкта відображає HTML для цього поля.

Щоб отримати єдине BoundField, використовуйте синтаксис пошуку словника у формі, використовуючи ім'я поля в якості ключа:

>>> form = ContactForm()
>>> print(form['subject'])
<input id="id_subject" type="text" name="subject" maxlength="100" />

Щоб отримати всі об'єкти BoundField, повторіть форму:

>>> form = ContactForm()
>>> for boundfield in form: print(boundfield)
<input id="id_subject" type="text" name="subject" maxlength="100" />
<input type="text" name="message" id="id_message" />
<input type="email" name="sender" id="id_sender" />
<input type="checkbox" name="cc_myself" id="id_cc_myself" />

Вихідний для цього поля характерний параметр auto_id об'єкта форми:

>>> f = ContactForm(auto_id=False)
>>> print(f['message'])
<input type="text" name="message" />
>>> f = ContactForm(auto_id='id_%s')
>>> print(f['message'])
<input type="text" name="message" id="id_message" />

2

Існує дуже простий в установці і відмінний інструмент зробив для Django , який я використовую для укладання і він може бути використаний для кожної структури у зовнішньому інтерфейсі , як Bootstrap, матеріалізувати, Фонд і т.д. Це називається віджет-твики Документація: Віджет Tweaks

  1. Ви можете використовувати його з загальними поглядами Джанго
  2. Або з власними формами:

від форм імпорту django

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    email = forms.EmailField(required=False)
    message = forms.CharField(widget=forms.Textarea)

Замість використання за замовчуванням:

{{ form.as_p }} or {{ form.as_ul }}

Ви можете редагувати його по-своєму, використовуючи атрибут render_field, який дає вам більш схожий на html спосіб стилізації, як у цьому прикладі:

template.html

{% load widget_tweaks %}

<div class="container">
   <div class="col-md-4">
      {% render_field form.subject class+="form-control myCSSclass" placeholder="Enter your subject here" %}
   </div>
   <div class="col-md-4">
      {% render_field form.email type="email" class+="myCSSclassX myCSSclass2" %}
   </div>
   <div class="col-md-4">
      {% render_field form.message class+="myCSSclass" rows="4" cols="6" placeholder=form.message.label %}
   </div>
</div>

Ця бібліотека дає вам можливість добре відокремити передній кінець від вашого сервера


1

У Django 1.10 (можливо, і раніше) ви можете це зробити наступним чином.

Модель:

class Todo(models.Model):
    todo_name = models.CharField(max_length=200)
    todo_description = models.CharField(max_length=200, default="")
    todo_created = models.DateTimeField('date created')
    todo_completed = models.BooleanField(default=False)

    def __str__(self):
        return self.todo_name

Форма:

class TodoUpdateForm(forms.ModelForm):
    class Meta:
        model = Todo
        exclude = ('todo_created','todo_completed')

Шаблон:

<form action="" method="post">{% csrf_token %}
    {{ form.non_field_errors }}
<div class="fieldWrapper">
    {{ form.todo_name.errors }}
    <label for="{{ form.name.id_for_label }}">Name:</label>
    {{ form.todo_name }}
</div>
<div class="fieldWrapper">
    {{ form.todo_description.errors }}
    <label for="{{ form.todo_description.id_for_label }}">Description</label>
    {{ form.todo_description }}
</div>
    <input type="submit" value="Update" />
</form>

0

Редагувати: Тут відповіли ще один (трохи кращий) спосіб виконання того, що я пропоную: Створення поля введення форми Django

Усі перераховані вище варіанти є приголомшливими, я просто подумав, що я б кинув цей, тому що він інший.

Якщо ви хочете, щоб у ваших формах була створена спеціальна стилізація, класи тощо, ви можете внести html-шаблон у свій шаблон, який відповідає вашому полі форми. Наприклад, для CharField (віджет за замовчуванням - TextInputскажімо), скажімо, що ви хочете ввести текст, що шукає завантажувальний текст. Ви зробите щось подібне:

<input type="text" class="form-control" name="form_field_name_here">

І якщо ви покладете назву поля форми, відповідає nameатрибуту html , (і віджет, ймовірно, повинен відповідати типу введення), Django запустить усі ті самі валідатори в цьому полі при запуску validateабо form.is_valid()і

Стилізація інших речей, таких як мітки, повідомлення про помилки та довідковий текст, не потребує особливих рішень, оскільки ви можете робити щось на зразок form.field.error.as_textі стилювати їх, як вам завгодно. Фактичні поля - це ті, що потребують певного змінення.

Я не знаю, чи це найкращий спосіб, чи спосіб, який я б рекомендував, але це спосіб, і це може бути правильним для когось.

Ось корисний посібник із стилізаційних форм, і він включає більшість відповідей, перелічених на SO (наприклад, використання attr у віджетах та налаштуваннях віджетів). https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html


0

Елементи віджетів для стилізації

Якщо ви хочете, щоб один екземпляр віджета виглядав інакше, ніж інший, вам потрібно буде вказати додаткові атрибути в той момент, коли об’єкт віджета буде ініційований і призначений в поле форми (і, можливо, додати деякі правила до ваших файлів CSS).

https://docs.djangoproject.com/en/2.2/ref/forms/widgets/

Для цього ви використовуєте аргумент Widget.attrs під час створення віджета:

class CommentForm(forms.Form):
    name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
    url = forms.URLField()
    comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))

Ви також можете змінити віджет у визначенні форми:

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()

    name.widget.attrs.update({'class': 'special'})
    comment.widget.attrs.update(size='40')

Або якщо поле не декларується безпосередньо у формі (наприклад, моделі формних полів), ви можете використовувати атрибут Form.fields:

class CommentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['name'].widget.attrs.update({'class': 'special'})
        self.fields['comment'].widget.attrs.update(size='40')

Потім Django включить додаткові атрибути у виведений результат:

>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40" required></td></tr>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.