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

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

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>

Например, как мне установить класс или идентификатор для subject, email, message чтобы предоставить внешнюю таблицу стилей?

Ответ 1

Взятый из моего ответа на: Как пометить поля формы с < 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. Если вам нужен полный контроль для полностью персонализированного рендеринга, это четко документировано

- ИЗМЕНИТЬ 2 ---
Добавлен новый способ указания виджета и attrs для ModelForm.

Ответ 2

Это можно сделать с помощью пользовательского шаблона фильтра. Подумайте, как визуализировать вашу форму

<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.

Ответ 3

Если вы не хотите добавлять какой-либо код в форму (как указано в комментариях к @shadfc Answer), это, безусловно, возможно, вот два варианта.

Сначала вы просто ссылаетесь на поля отдельно в 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;}

Ответ 4

Вы можете сделать следующее:

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

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

Игнас

Ответ 5

В this в блоге вы можете добавлять классы 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"}}

Ответ 6

Вы можете использовать эту библиотеку: 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" }}

Ответ 7

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

<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}} просто выводит тег ввода, а не метку и т.д.).

Ответ 8

Не видел этого действительно...

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" />

Ответ 9

Вам не нужно переопределять класс формы __init__, потому что Django устанавливает атрибуты name и id в HTML input s. У вас может быть такой CSS:

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

Ответ 10

Одним из решений является использование 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>

Это позволяет избежать уродства, связанного с детализацией стилей в вашей бизнес-логике.

Ответ 11

Существует очень простой в установке и отличный инструмент для Django, который я использую для стилизации, и его можно использовать для всех интерфейсных фреймворков, таких как Bootstrap, Materialize, Foundation и т.д. Это называется виджетами-настройками. Документация: Widget Tweaks

  • Вы можете использовать его в общих представлениях Django
  • Или с вашими собственными формами:

из форм импорта 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>

Эта библиотека дает вам возможность хорошо отделить ваш интерфейс от вашего бэкэнда

Ответ 12

В 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>

Ответ 13

Изменить: Другой (немного лучший) способ сделать то, что я предлагаю, ответ здесь: 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 и form.field.error.as_text их так, как вам form.field.error.as_text. Фактические поля - те, которые требуют некоторого возни.

Я не знаю, является ли это лучшим способом или способом, который я бы порекомендовал, но это способ, и это может быть правильным для кого-то.

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

Ответ 14

я могу использовать Reactjs для этой цели? вместо стайлинга форм

Ответ 15

Стилизация экземпляров виджета

Если вы хотите, чтобы один экземпляр виджета отличался от другого, вам нужно будет указать дополнительные атрибуты в момент создания экземпляра объекта виджета и присвоения его полю формы (и, возможно, добавить некоторые правила в ваши 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>

Ответ 16

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

    class MyForm(forms.Form):
         name = forms.CharField(widget=forms.TextInput(attr={'class':'name'}))
         message = forms.CharField(widget=forms.Textarea(attr={'class':'message'}))

В вашем HTML-поле сделайте что-то вроде:

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

Затем в вашем CSS напишите что-то вроде:

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

Надеюсь, что этот ответ стоит попробовать! Обратите внимание, что вы должны написать свои представления для отображения HTML файла, который содержит форму.