Макеты¶
Основы¶
Django-crispy-forms определяет еще один мощный класс под названием Layout
, который позволяет вам изменять способ отображения полей формы. Это позволяет вам установить порядок полей, обернуть их в div’ы или другие структуры, добавить html, установить идентификаторы, классы или атрибуты на то, что вы хотите, и т.д. И все это без написания собственного шаблона формы, используя программные макеты. Просто прикрепите макет к хелперу, макеты необязательны, но, вероятно, это самое мощное, что может предложить django-crispy-forms.
Layout
строится с помощью объектов компоновки, которые можно представить как компоненты формы.
Все эти компоненты будут описаны позже в Универсальные объекты компоновки, сейчас о них нужно знать то, что каждый компонент отображает свой шаблон и имеет свое назначение. Давайте напишем пару различных макетов для нашей формы, продолжая пример с классом формы (обратите внимание, что полная форма снова не показана).
Некоторые объекты макета специфичны для пакета шаблонов. Например, ButtonHolder
предназначен для uni_form
template_pack, а FormActions
- для bootstrap
template pack.
Давайте добавим макет в наш помощник:
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset, ButtonHolder, Submit
class ExampleForm(forms.Form):
[...]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(
'first arg is the legend of the fieldset',
'like_website',
'favorite_number',
'favorite_color',
'favorite_food',
'notes'
),
ButtonHolder(
Submit('submit', 'Submit', css_class='button white')
)
)
Когда мы отображаем форму сейчас, используя:
{% load crispy_forms_tags %}
{% crispy example_form %}
Мы получим поля, обернутые в набор полей, легенда которого будет установлена на „first arg - легенда набора полей“. Порядок полей будет следующим: like_website
, favorite_number
, favorite_color
, favorite_food
и notes
. Мы также получаем кнопку отправки, обернутую в <div class="buttonHolder">
, которую uni-form CSS позиционирует приятным образом. Для этой кнопки установлен класс CSS button white
.
Это только вершина айсберга: теперь представьте, что вы хотите добавить объяснение того, что такое заметки, вы можете использовать HTML
layout object:
Layout(
Fieldset(
'Tell us your favorite stuff {{ username }}',
'like_website',
'favorite_number',
'favorite_color',
'favorite_food',
HTML("""
<p>We use notes to get better, <strong>please help us {{ username }}</strong></p>
"""),
'notes'
)
)
Как вы заметили, легенда набора полей учитывает контекст, и вы можете написать ее так, как если бы это был фрагмент шаблона, в котором будет отображаться форма. Объект HTML
добавит сообщение перед вводом примечаний, и он также учитывает контекст. Обратите внимание, как можно обернуть объекты макета в другие объекты макета. Объекты макета Fieldset
, Div
, MultiField
и ButtonHolder
могут содержать внутри себя другие объекты макета. Давайте сделаем альтернативный макет для той же формы:
Layout(
MultiField(
'Tell us your favorite stuff {{ username }}',
Div(
'like_website',
'favorite_number',
css_id = 'special-fields'
),
'favorite_color',
'favorite_food',
'notes'
)
)
На этот раз мы используем MultiField
, который представляет собой объект макета, который, как правило, можно использовать в тех же местах, что и Fieldset
. Основное отличие заключается в том, что здесь все поля обернуты в div, и при возникновении ошибок в отправке формы они отображаются в списке, а не вокруг каждого поля. Иногда лучший способ понять, что делают объекты компоновки, - это просто попробовать их и немного поиграть с ними.
Атрибуты объектов макета¶
Всем объектам макета можно задать kwargs, которые будут использоваться в качестве атрибутов HTML. Например, если вы хотите отключить автозаполнение для поля, вы можете сделать следующее:
Field('field_name', autocomplete='off')
Если вы хотите задать html-атрибуты, разделяя слова дефисами, например data-name
, поскольку Python не поддерживает дефисы в аргументах ключевых слов, а дефисы являются обычным обозначением в HTML, подчеркивания будут переведены в дефисы, поэтому вы сделаете:
Field('field_name', data_name="whatever")
Поскольку class
является зарезервированным ключевым словом в Python, для него нужно использовать css_class
. Например:
Field('field_name', css_class="black-fields")
А атрибут id устанавливается с помощью css_id
:
Field('field_name', css_id="custom_field_id")
Универсальные объекты компоновки¶
Они находятся в модуле crispy_forms.layout
. Это объекты верстки, которые не являются специфическими для пакета шаблонов. Мы будем рассматривать их по одному, показывая примеры использования:
Div: Он оборачивает поля в
<div>
:Div('form_field_1', 'form_field_2', 'form_field_3', ...)
NOTE В основном во всех объектах макета можно задать kwargs, которые будут использоваться в качестве атрибутов HTML. Поскольку class
является зарезервированным ключевым словом в Python, для него нужно использовать css_class
. Например:
Div('form_field_1', style="background: white;", title="Explication title", css_class="bigdivs")
HTML: Очень мощный объект компоновки. Используйте его для рендеринга чистого html-кода. Фактически он ведет себя как шаблон Django и имеет доступ ко всему контексту страницы, на которой отображается форма. Этот объект макета не принимает никаких дополнительных параметров, кроме html для рендеринга, вы не можете установить атрибуты html, как в
Div
:HTML("{% if success %} <p>Operation was successful</p> {% endif %}")
Предупреждение
Обратите внимание, что это отображается в отдельном шаблоне, поэтому если вы используете пользовательские теги шаблонов или фильтры, не забудьте добавить свои
{% load custom_tags %}
.
Поле: Чрезвычайно полезный объект компоновки. Вы можете использовать его для установки атрибутов поля или отображения конкретного поля с помощью пользовательского шаблона. Таким образом вы избежите необходимости явно переопределять виджет поля и передавать уродливый словарь
attrs
:Field('password', id="password-field", css_class="passwordfields", title="Explanation") Field('slider', template="custom-slider.html")
Этот объект компоновки можно использовать для простого расширения виджетов Django. Если вы хотите отобразить поле формы Django как скрытое, вы можете просто сделать:
Field('field_name', type="hidden")
Если вам нужны атрибуты HTML5, вы можете легко сделать это, используя подчеркивание data_name
kwarg здесь превратится в data-name
в вашем сгенерированном html:
Field('field_name', data_name="special")
Поля в bootstrap обернуты в <div class="control-group">
. Вы можете захотеть установить дополнительные классы в этом div, для этого сделайте:
Field('field_name', wrapper_class="extra-class")
Submit: Используется для создания кнопки отправки. Первый параметр - атрибут
name
кнопки, второй параметр - атрибутvalue
:Submit('search', 'SEARCH')
Переводится как:
<input type="submit" name="search" value="SEARCH" class="submit submitButton" id="submit-id-search" />
Скрытый: Используется для создания скрытого ввода:
Hidden('name', 'value')
Кнопка: Создает кнопку:
Button('name', 'value')
Сброс: Используется для создания входа сброса:
reset = Reset('name', 'value')
Fieldset: Он оборачивает поля в
<fieldset>
. Первый параметр - текст для легенды набора полей, как мы уже говорили, он ведет себя как шаблон Django:Fieldset("Text for the legend {{ username }}", 'form_field_1', 'form_field_2' )
Объекты макета униформы¶
Эти живут в модуле crispy_forms.layout
. Возможно, в будущем они будут перенесены в модуль uni_form
:
ButtonHolder: Он оборачивает поля в
<div class=”buttonHolder”>
, которые uni-form позиционирует красивым образом. Именно сюда помещаются кнопки отправки формы в uni-form:ButtonHolder( HTML('<span class="hidden">✓ Saved data</span>'), Submit('save', 'Save') )
MultiField: Обертывает поля в
<div>
с меткой сверху. При возникновении ошибок при отправке формы отображает их в виде списка, а не каждую из них вокруг поля:MultiField("Text for the label {{ username }}", 'form_field_1', 'form_field_2' )
Объекты макета Bootstrap¶
Эти живут под модулем crispy_forms.bootstrap
.
FormActions: Обертывает поля в
<div class="form-actions">
. Обычно используется для обертывания кнопок формы:FormActions( Submit('save', 'Save changes'), Button('cancel', 'Cancel') )
AppendedText: Эта функция отображает вводимый в bootstrap добавляемый текст. Первым параметром является имя поля, к которому нужно добавить добавляемый текст, затем добавляемый текст, который может быть HTML. Есть дополнительный параметр
active
, по умолчанию установленный вFalse
, который можно установить в булево значение, чтобы сделать добавленный текст активным:AppendedText('field_name', 'appended text to show') AppendedText('field_name', '$', active=True)
PrependedText: Создает вводимый в bootstrap текст. Первым параметром является имя поля, к которому нужно добавить добавляемый текст, затем добавляемый текст, который может иметь вид HTML. Есть дополнительный параметр
active
, по умолчанию установленный вFalse
, который можно установить в булево значение, чтобы сделать вводимый текст активным:PrependedText('field_name', '<b>Prepended text</b> to show') PrependedText('field_name', '@', placeholder="username")
PrependedAppendedText: Выводит комбинированный предактивированный и апплицированный текст. Первым параметром является имя поля, затем предваряющий текст и, наконец, добавляемый текст:
PrependedAppendedText('field_name', '$', '.00'),
InlineCheckboxes: Он отображает поле Django
forms.MultipleChoiceField
, используя встроенные флажки:InlineCheckboxes('field_name')
InlineRadios: Он отображает поле Django
forms.ChoiceField
с его виджетом, установленным наforms.RadioSelect
, используя встроенные радиокнопки:InlineRadios('field_name')
StrictButton: Он отображает кнопку, используя
<button>
html, а неinput
. По умолчаниюtype
устанавливается вbutton
, аclass
устанавливается вbtn
:StrictButton("Button's content", name="go", value="go", css_class="extra") StrictButton('Success', css_class="btn-success")
Поле с кнопками: Вы можете создать вход, связанный с кнопками:
FieldWithButtons('field_name', StrictButton("Go!"))
Таб и TabHolder:
Tab
отображает вкладку, различные вкладки должны быть обернуты вTabHolder
для автоматического функционирования javascript, также вам понадобитсяbootstrap-tab.js
, включенный в ваши статические файлы:TabHolder( Tab('First Tab', 'field_name_1', Div('field_name_2') ), Tab('Second Tab', Field('field_name_3', css_class="extra") ) )
Accordion & AccordionGroup:
AccordionGroup
отображает панель аккордеона, различные группы должны быть обернуты вAccordion
для автоматического функционирования javascript, также вам понадобитсяbootstrap-tab.js
, включенный в ваши статические файлы:Accordion( AccordionGroup('First Group', 'radio_buttons' ), AccordionGroup('Second Group', Field('field_name_3', css_class="extra") ) )
Алерт:
Alert
генерирует разметку в виде диалога предупреждения:Alert(content='<strong>Warning!</strong> Best check yo self, you're not looking too good.')
UneditableField:
UneditableField
отображает поле с возможностью отключения, используя bootstrapuneditable-input
class:UneditableField('text_input', css_class='form-control-lg')
Переопределение шаблонов объектов компоновки¶
Упомянутый набор Универсальные объекты компоновки был тщательно разработан, чтобы быть гибким, совместимым со стандартами и поддерживать возможности формы Django. Каждый объект Layout связан с отдельным шаблоном, который находится в каталоге templates/{{ TEMPLATE_PACK_NAME }}/layout/
.
Некоторые опытные пользователи могут захотеть использовать свои собственные шаблоны, чтобы адаптировать объекты компоновки к своему использованию или необходимости. Существует три способа переопределить шаблон, используемый объектом компоновки.
Глобально: Вы переопределяете шаблон объекта макета, для всех экземпляров этого объекта макета вы используете:
from crispy_forms.layout import Div Div.template = 'my_div_template.html'
Индивидуально: Вы можете переопределить шаблон для определенного объекта макета в макете:
Layout( Div( 'field1', 'field2', template='my_div_template.html' ) )
Переопределение каталога шаблонов: Это означает имитацию структуры каталога crispy-forms в вашем проекте, а затем копирование туда шаблонов, которые вы хотите переопределить, и окончательное редактирование этих копий. Если вы используете этот подход, лучше просто скопировать и отредактировать шаблоны, которые вы будете настраивать, а не все.
Переопределение шаблонов проекта¶
Вам нужно различать шаблоны объектов макета и шаблоны django-crispy-forms. Есть некоторые шаблоны, которые живут в templates/{{ TEMPLATE_PACK_NAME }}
, которые определяют структуру формы/формсета, как отображаются поля или ошибки и т.д. Они добавляют очень мало логики и являются базовыми обертками для django-crispy-forms. Они добавляют очень мало логики и являются практически базовыми обертками для остальных возможностей django-crispy-forms. Чтобы переопределить эти параметры, у вас есть две возможности:
Атрибуты template и field_template в
FormHelper
: Начиная с версии 1.3.0 вы можете переопределить шаблон формы/формсета и шаблон поля с помощью вспомогательных атрибутов, см. раздел Атрибуты помощника, которые вы можете установить. С помощью этого вы можете изменить одну конкретную форму или все формы вашего проекта (например, создав пользовательский базовый класс FormHelper).Переопределение каталога шаблонов: Это работает так же, как описано в разделе Переопределение шаблонов объектов компоновки. Если вы адаптируете шаблоны crispy-forms к популярному пакету шаблонов с открытым исходным кодом, который вы используете, отправьте его, чтобы больше людей могли воспользоваться им.
Создание пакета шаблонов: Возможно, вы захотите использовать crispy-формы с вашим любимым CSS-фреймворком или CSS вашей компании. Для этого вам нужно быть хорошо знакомым с crispy-forms, объектами макета и их шаблонами. Вы, вероятно, захотите начать с одного из существующих пакетов шаблонов, вероятно,
bootstrap
. Представьте, что ваш пакет шаблонов называетсяchocolate
, это означает, что вы, вероятно, захотите, чтобы ваш корневой каталог был назван так же. Для использования вашего пакета шаблонов, вам нужно будет установить переменнуюCRISPY_TEMPLATE_PACK = 'chocolate'
в вашем файле настроек, а также установитьCRISPY_ALLOWED_TEMPLATE_PACKS = ('bootstrap', 'chocolate')
. Таким образом, crispy-forms будет знать, что вы хотите использовать свой собственный пакет шаблонов, что это разрешенный пакет и где его искать.
Создание собственных объектов макета¶
Универсальные объекты компоновки, поставляемые в комплекте с django-crispy-forms, представляют собой набор наиболее заметных компонентов, которые строят форму. Вы, вероятно, сможете сделать все, что вам нужно, комбинируя их. В любом случае, вы можете захотеть создать свои собственные компоненты, для этого вам понадобится хорошее знание django-crispy-forms. Каждый объект макета должен иметь метод render
. Его прототип должен быть:
def render(self, form, form_style, context):
Официальные объекты макета находятся в layout.py
и bootstrap.py
, вы можете взглянуть на них, чтобы полностью понять, как действовать дальше. Но в общих чертах, объект макета - это шаблон, отображаемый с некоторыми переданными параметрами.
Если вам пришла в голову хорошая идея и вы разработали объект компоновки, который, по вашему мнению, может быть полезен другим, пожалуйста, откройте проблему или отправьте запрос на исправление, чтобы django-crispy-forms стал лучше.
Составление макетов¶
Представьте, что у вас есть несколько форм, которые используют большой кусок одного и того же макета. Есть простой способ создать Layout
, повторно использовать и расширить его. Вы можете иметь Layout
как компонент другого Layout
. Вы можете создать этот общий кусок разными способами. Как отдельный класс:
class CommonLayout(Layout):
def __init__(self, *args, **kwargs):
super().__init__(
MultiField("User data",
'username',
'lastname',
'age'
)
)
Может быть, достаточно экземпляра объекта:
common_layout = Layout(
MultiField("User data",
'username',
'lastname',
'age'
)
)
Тогда вы можете сделать следующее:
helper.layout = Layout(
CommonLayout(),
Div(
'favorite_food',
'favorite_bread',
css_id = 'favorite-stuff'
)
)
Или:
helper.layout = Layout(
common_layout,
Div(
'professional_interests',
'job_description',
)
)
Мы определили макет и использовали его как часть другого макета, что означает, что эти два макета будут начинаться одинаково, а затем расширять макет разными способами.