CSS-стилизация в формах Django

150

Я хотел бы стилизовать следующее:

forms.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чтобы обеспечить внешнюю таблицу стилей?

David542
источник

Ответы:

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

--- РЕДАКТИРОВАТЬ ---
Вышесказанное - самое простое изменение кода исходного вопроса, которое выполняет заданное. Это также удерживает вас от повторения, если вы повторно используете форму в других местах; ваши классы или другие атрибуты просто работают, если вы используете методы формы Django as_table / as_ul / as_p. Если вам нужен полный контроль для полностью настраиваемого рендеринга, это четко задокументировано

- РЕДАКТИРОВАТЬ 2 ---
Добавлен новый способ указать виджет и атрибуты для ModelForm.

shadfc
источник
27
Хотя не рекомендуется смешивать презентацию с бизнес-логикой.
Торстен Энгельбрехт
8
Как эта презентация? Вы даете элементу класс, который является просто идентификатором или категоризацией. Вы все еще должны определить, что это делает в другом месте
shadfc
9
Да и нет. Первые CSS-классы по соглашению используются для стилизации, если вам нужен уникальный идентификатор, который лучше использовать id. Во-вторых, это обычно ответная сторона шаблона, чтобы выполнить это, особенно, если вы собираетесь получить доступ к этому классу через методы внешнего интерфейса (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.

Charlesthk
источник
5
Это одно из самых простых и понятных решений
пользователь
5
Этот ответ должен быть главным ответом !!! Это действительно чище, чем предложенное Django решение! Молодцы @Charlesthk
Дэвид Д.
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), - но достаточно просто ссылаться на все поля по идентификатору. в вашем CSS вот так:

#id_subject, #id_email, #email_message 
{color: red;}
Джон С
источник
Я попробовал ваше второе решение, но оно не сработало. Я создал класс для id_email, и он не дал никаких результатов.
почти новичок
@almostabeginner Одна вещь, которую я могу предложить для отладки - как только вы увидите страницу в браузере, используйте View Page Source (обычно щелкнув правой кнопкой мыши) и посмотрите на фактическую полную страницу, которую генерирует Django. Посмотрите, существуют ли поля с ожидаемым идентификатором или идентификатором класса . Также большинство браузеров (возможно, установив плагин) могут запускать отладчик, который показывает вам CSS, который применяется к странице, также полезно посмотреть, что происходит.
Джон C
@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})

Поместите это в папку templatetags / вашего приложения, и теперь вы можете сделать

{{field|addcss:"form-control"}}
aashanand
источник
2
это должно было быть принято как реальный ответ на этот пост :)
mvdb
Лучшее решение на сегодняшний день.
Моды против
1
Отлично, спасибо! Не забудьте загрузить тег. Кроме того, в Django 2.1 единственный способ заставить Django найти шаблон - добавить опцию в settings.py: 'library': {'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'})

Надеюсь, что это работает.

Игнас

Игнас Бутенас
источник
Спасибо, игнас. Точный ответ!
Рудреш Айгаонкар
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, оно без добавления дополнительной библиотеки :)
David D.
@DavidW .: Да, но в настройках виджетов есть много других фильтров, например render_field.
Мрдалири
5

Ты можешь сделать:

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

Затем вы можете добавить классы / идентификаторы, например, к <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-файла, который содержит форму.

очаг гиперемии
источник
Спасибо. но как я могу написать конкретный текст метки?
Гакеко Беци
2

Вам может не понадобиться переопределять ваш класс формы ' __init__, потому что Django устанавливает name& idатрибуты в HTML- inputфайлах. Вы можете использовать CSS следующим образом:

form input[name='subject'] {
    font-size: xx-large;
}
tehfink
источник
1
Чтобы добавить к этому. Учитывая "subject = forms ...", id = "id_subject" и name = "subject" является соглашением Django для этих атрибутов. Поэтому вы также должны быть в состоянии сделать #id_subject {...}
solartic
@solartic: Ты прав, спасибо. Я не упоминал об этом, потому что idполе, созданное Django для наборов форм, становится довольно волосатым…
tehfink
2

Не видел этого на самом деле ...

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

Более гранулированный выход

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

class 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" />
BilliAm
источник
2

Существует очень простой в установке и прекрасный инструмент, созданный для Django, который я использую для стилей, и его можно использовать для любого фреймворка, такого как Bootstrap, Materialize, Foundation и т. Д. Он называется widget-tweaks Документация: Widget 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>
MadPhysicist
источник
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>
Фреман Чжан
источник