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

94

Как мне создать следующее:

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

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

Теги:

12 ответов

122
Лучший ответ

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

  • 20
    Хотя не рекомендуется смешивать презентацию с бизнес-логикой.
  • 6
    Как эта презентация? Вы даете элементу класс, который является просто идентификатором или категоризацией. Вы все еще должны определить, что это делает в другом месте
Показать ещё 6 комментариев
69

Это можно сделать с помощью настраиваемого фильтра шаблонов. учитывая, что вы делаете свою форму следующим образом:

<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 будет отображаться с классом css "MyClass".

Надеюсь на эту помощь.

  • 5
    Это одно из самых простых и понятных решений
  • 5
    Этот ответ должен быть главным ответом !!! Это действительно чище, чем предложенное Django решение! Молодцы @Charlesthk
Показать ещё 2 комментария
22

Если вы не хотите добавлять какой-либо код в форму (как указано в комментариях к @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;}
  • 0
    Я попробовал ваше второе решение, но оно не сработало. Я создал класс для id_email, и он не дал никаких результатов.
  • 0
    @almostabeginner Одна вещь, которую я могу предложить для отладки - как только вы увидите страницу в браузере, используйте View Page Source (обычно щелкнув правой кнопкой мыши) и посмотрите на фактическую полную страницу, которую генерирует Django. Посмотрите, существуют ли поля с ожидаемым идентификатором или идентификатором класса . Также большинство браузеров (возможно, с помощью установки плагина) могут запускать отладчик, который показывает вам CSS, который применяется к странице, также полезно посмотреть, что происходит.
Показать ещё 2 комментария
9

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

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

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

Игнас

  • 0
    Спасибо, игнас. Точный ответ!
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" }}
  • 1
    Взгляните на решение Charlesthk, оно без добавления дополнительной библиотеки :)
  • 0
    @DavidW .: Да, но в настройках виджетов есть много других фильтров, таких как render_field .
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"}}
  • 2
    это должно было быть принято как реальный ответ на этот пост :)
  • 0
    Лучшее решение на сегодняшний день.
4

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

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

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

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

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

Существует очень простой в установке и отличный инструмент для 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>

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

0

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

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

0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню