Работа с формами
О документе
Этот документ предоставляет введение в основы веб-форм и их обработку в Django. Для более подробного ознакомления со специфическими областями API форм см. API форм, Поля форм и Валидация форм и полей.
Если вы не планируете создавать веб-сайты и приложения, которые только публикуют контент и не принимают ввод от посетителей, вам необходимо понять и использовать формы.
Django предоставляет набор инструментов и библиотек, которые помогут вам создавать формы для приема ввода от посетителей сайта, а затем обрабатывать и реагировать на этот ввод.
HTML-формы
В HTML форма представляет собой набор элементов внутри <form>...</form> , которые позволяют пользователю выполнять действия, такие как ввод текста, выбор параметров, манипулирование объектами или элементами управления и т. д., а затем отправлять эту информацию обратно на сервер.
Некоторые из этих элементов интерфейса формы — текстовые поля или флажки — встроены в сам HTML. Другие гораздо сложнее; интерфейс, который отображает календарь выбора даты или позволяет перемещать ползунок или управлять элементами управления, как правило, использует JavaScript и CSS, а также HTML-элементы форм <input> для достижения этих эффектов.
Помимо своих <input> элементов, форма должна указывать две вещи:
- куда: URL, на который должны быть возвращены данные, соответствующие вводу пользователя
- как: метод HTTP, с помощью которого данные должны быть возвращены
Например, форма входа в систему для административной панели Django содержит несколько <input> элементов: одно type="text" для имени пользователя, одно type="password" для пароля и одно type="submit" для кнопки «Войти». Она также содержит некоторые скрытые текстовые поля, которые пользователь не видит, которые Django использует для определения последующих действий.
Она также сообщает браузеру, что данные формы должны быть отправлены на URL, указанный в <form> атрибуте action - /admin/ - и что они должны быть отправлены с использованием механизма HTTP, указанного в method атрибуте - post.
Когда срабатывает элемент <input type="submit" value="Log in"> , данные возвращаются в /admin/.
GET и POST
GET и POST являются единственными методами HTTP, которые следует использовать при работе с формами.
Форма входа в систему Django возвращается с использованием метода POST , в котором браузер собирает данные формы, кодирует их для передачи, отправляет на сервер и получает от него ответ.
GET, в отличие от этого, объединяет отправленные данные в строку и использует ее для составления URL. URL содержит адрес, куда должны быть отправлены данные, а также ключи и значения данных. Вы можете увидеть это в действии, если выполните поиск в документации Django, что приведет к URL-адресу в формате https://docs.djangoproject.com/search/?q=forms&release=1.
GET и POST обычно используются для разных целей.
Любой запрос, который может быть использован для изменения состояния системы (например, запрос, который вносит изменения в базу данных), должен использовать POST. GET следует использовать только для запросов, которые не влияют на состояние системы.
GET также не подходит для формы пароля, так как пароль будет отображаться в URL, а следовательно, и в истории браузера и журналах сервера — все в открытом виде. Он также не подходит для больших объемов данных или для двоичных данных, таких как изображение. Веб-приложение, использующее запросы GET для форм администратора, представляет собой угрозу безопасности: злоумышленнику легко может быть подделано запросы формы для получения доступа к чувствительным частям системы. POST, в сочетании с другими мерами защиты, такими как защита от CSRF в Django, предоставляет больший контроль над доступом.
С другой стороны, GET подходит для таких вещей, как веб-форма поиска, потому что URL-адреса, представляющие запрос GET , легко закладки, могут быть распространены или повторно отправлены.
Роль Django в формах
Обработка форм — сложная задача. Рассмотрим административную панель Django, где множество данных различных типов могут потребоваться подготовить для отображения в форме, преобразовать в HTML, отредактировать с помощью удобного интерфейса, вернуть на сервер, валидировать и очистить, а затем сохранить или передать для дальнейшей обработки.
Функциональность форм Django может упростить и автоматизировать значительные части этой работы и сделать это более безопасно, чем большинство программистов смогли бы реализовать в коде, написанном ими самими.
Django обрабатывает три разных части работы, связанной с формами:
- подготовка и перестройка данных для их готовности к рендерингу
- создание HTML-форм для данных
- получение и обработка отправленных форм и данных от клиента
Возможно написать код, который сделает все это вручную, но Django может позаботиться обо всем за вас.
Формы в Django
Мы кратко описали HTML-формы, но HTML-форма <form> — это только часть механизма, который требуется.
В контексте веб-приложения «форма» может относиться к этому HTML-элементу <form>, к классу Django Form, который его генерирует, к структурированным данным, возвращаемым при ее отправке, или к работе с этими частями как целым.
Класс Django Form
В основе этой системы компонентов лежит класс Django Form. Подобно тому, как модель Django описывает логическую структуру объекта, его поведение и способ представления его частей для нас, класс Form описывает форму и определяет, как она работает и отображается.
Подобно тому, как поля класса модели сопоставляются с полями базы данных, поля класса формы сопоставляются с элементами HTML-форм <input>. (Класс ModelForm сопоставляет поля класса модели с элементами HTML-форм <input> через класс Form; на этом основана административная панель Django.)
Поля формы сами являются классами; они управляют данными формы и выполняют валидацию при отправке формы. DateField и FileField обрабатывают разные типы данных и выполняют разные операции с ними.
Поле формы представляется пользователю в браузере в виде HTML-«виджета» — элемента интерфейса пользователя. Каждый тип поля имеет соответствующий по умолчанию класс виджета, но при необходимости их можно переопределить.
Создание, обработка и рендеринг форм
При рендеринге объекта в Django, как правило:
- получаем его в представлении (например, извлекаем из базы данных)
- передаем его в контекст шаблона
- преобразуем его в HTML-разметку с помощью переменных шаблона
Рендеринг формы в шаблоне включает почти ту же работу, что и рендеринг любого другого объекта, но есть некоторые ключевые отличия.
В случае экземпляра модели, не содержащего данных, редко бывает полезно выполнять какие-либо действия с ним в шаблоне. С другой стороны, имеет смысл отобразить пустую форму — именно это мы делаем, когда хотим, чтобы пользователь ее заполнил.
Итак, когда мы обрабатываем экземпляр модели в представлении, обычно получаем его из базы данных. Когда мы работаем с формой, обычно создаем ее экземпляр в представлении.
При создании экземпляра формы мы можем выбрать, оставить ее пустой или предварительно заполнить, например, данными:
- из сохраненного экземпляра модели (как в случае с формами администратора для редактирования)
- данными, собранными из других источников
- данными, полученными из предыдущей отправки HTML-формы
Последний из этих случаев наиболее интересен, так как он позволяет пользователям не только читать веб-сайт, но и отправлять на него информацию.
Создание формы
Работа, которую необходимо выполнить
Предположим, вы хотите создать простую форму на своем веб-сайте для получения имени пользователя. В вашем шаблоне вам понадобится что-то вроде этого:
<form action="/your-name/" method="post">
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
<input type="submit" value="OK">
</form>
Это сообщает браузеру вернуть данные формы на URL /your-name/, используя метод POST . Он отобразит текстовое поле с меткой «Ваше имя:» и кнопку «ОК». Если в контексте шаблона есть переменная current_name , она будет использована для предварительного заполнения поля your_name.
Вам понадобится представление, которое отображает шаблон, содержащий HTML-форму, и которое может предоставить поле current_name соответствующим образом.
Когда форма отправляется, запрос POST , отправленный на сервер, будет содержать данные формы.
Теперь вам также понадобится представление, соответствующее URL /your-name/ , которое найдет соответствующие пары ключ/значение в запросе и обработает их.
Это очень простая форма. На практике форма может содержать десятки или сотни полей, многие из которых могут потребоваться предварительно заполнить, и мы можем ожидать, что пользователь несколько раз пройдёт цикл редактирования-отправки, прежде чем закончит операцию.
Возможно, нам понадобится валидация, происходящая в браузере, даже перед отправкой формы; мы можем захотеть использовать гораздо более сложные поля, которые позволят пользователю, например, выбирать даты из календаря и так далее.
В этот момент гораздо проще поручить большую часть этой работы Django.
Создание формы в Django
Класс Form
Мы уже знаем, как должен выглядеть наш HTML-формуляр. Наш отправной пункт для него в Django — это:
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
Это определяет класс Form с одним полем (your_name). Мы применили удобочитаемое имя поля, которое будет отображаться в <label> при его рендеринге (хотя в этом случае, label, который мы указали, фактически совпадает с тем, который был бы сгенерирован автоматически, если бы мы его опустили).
Максимальная допустимая длина поля определяется max_length. Это делает два дела. Оно устанавливает maxlength="100" на HTML <input> (чтобы браузер в первую очередь предотвратил ввод пользователем большего количества символов). Это также означает, что когда Django получит форму обратно от браузера, он проверит длину данных.
Объект Form имеет метод is_valid(), который выполняет процедуры валидации для всех его полей. Когда этот метод вызывается, если все поля содержат допустимые данные, он:
- вернет
True - поместит данные формы в атрибут
cleaned_data.
Весь формуляр, при первом рендеринге, будет выглядеть так:
<label for="your_name">Your name: </label> <input id="your_name" type="text" name="your_name" maxlength="100" required>
Обратите внимание, что он не включает теги <form>, или кнопку отправки. Их нужно будет предоставить самим в шаблоне.
Обработка формы
Данные формы, отправленные обратно на веб-сайт Django, обрабатываются представлением, обычно тем же представлением, которое опубликовало форму. Это позволяет нам повторно использовать часть логики.
Для обработки формы нам нужно инициализировать ее в представлении для URL-адреса, где мы хотим ее опубликовать:
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
Если мы попадаем в это представление с GET запросом, оно создаст пустой экземпляр формы и поместит его в контекст шаблона для рендеринга. Вот что можно ожидать при первом посещении URL-адреса.
Если форма отправляется с помощью POST запроса, представление снова создаст экземпляр формы и заполнит его данными из запроса: form =
NameForm(request.POST) Это называется «привязкой данных к форме» (теперь это связанная форма).
Мы вызываем метод is_valid() формы; если он не True, мы возвращаемся в шаблон с формой. На этот раз форма больше не пустая (несвязанная), поэтому HTML-форма будет заполнена ранее отправленными данными, где её можно будет редактировать и исправлять по мере необходимости.
Если is_valid() является True, мы сможем найти все проверенные данные формы в атрибуте cleaned_data. Мы можем использовать эти данные для обновления базы данных или для других операций, прежде чем отправлять HTTP-перенаправление браузеру, сообщая ему, куда перейти дальше.
Шаблон
Нам не нужно делать многого в нашем name.html шаблоне:
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
Все поля формы и их атрибуты будут распакованы в HTML-разметку из этого {{ form }} языком шаблонов Django.
Формы и защита от межсайтовых поддельных запросов
Django поставляется с удобной в использовании защитой от межсайтовых поддельных запросов. При отправке формы через POST с включенной защитой от CSRF необходимо использовать тег шаблона csrf_token, как в предыдущем примере. Однако, поскольку защита от CSRF не напрямую связана с формами в шаблонах, этот тег опущен из последующих примеров в данном документе.
HTML5 типы ввода и валидация браузера
Если ваша форма содержит URLField, EmailField или любой целочисленный тип поля, Django будет использовать url, email и number HTML5 типы ввода. По умолчанию браузеры могут применять собственную валидацию для этих полей, которая может быть строже, чем валидация Django. Если вы хотите отключить это поведение, установите атрибут novalidate на теге form, или укажите другой виджет для поля, например TextInput.
Теперь у нас есть рабочая веб-форма, описанная Django Form, обработанная представлением и отображённая как HTML <form>.
Этого достаточно для начала, но фреймворк форм предоставляет гораздо больше возможностей. Как только вы поймёте основы описанного выше процесса, вы должны быть готовы понять другие функции системы форм и готовы узнать немного больше о лежащих в её основе механизмах.
Подробнее о классах Django Form
Все классы форм создаются как подклассы либо django.forms.Form, либо django.forms.ModelForm. Можно считать, что ModelForm является подклассом Form. Form и ModelForm на самом деле наследуют общие функции от (приватного) BaseForm класса, но эта деталь реализации редко важна.
Модели и формы
Если ваша форма предназначена для непосредственного добавления или редактирования модели Django, ModelForm сэкономит вам много времени, усилий и кода, так как она создаст форму вместе с соответствующими полями и их атрибутами, используя класс Model.
Связанные и несвязанные экземпляры формы
Различие между связанными и несвязанными формами важно:
- Несвязанная форма не имеет связанных с ней данных. При рендеринге для пользователя она будет пустой или содержать значения по умолчанию.
- Связанная форма имеет отправленные данные и, следовательно, может использоваться для определения того, являются ли эти данные корректными. Если рендерится некорректная связанная форма, она может содержать встроенные сообщения об ошибках, которые подскажут пользователю, какие данные следует исправить.
Атрибут is_bound формы укажет, связаны ли с ней данные или нет.
Подробнее о полях
Рассмотрим более полезную форму, чем наш минимальный пример выше, которую мы можем использовать для реализации функциональности «свяжитесь со мной» на личном веб-сайте:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
Наша предыдущая форма использовала одно поле, your_name, CharField. В этом случае наша форма имеет четыре поля: subject, message, sender и cc_myself. CharField, EmailField и BooleanField — всего лишь три из доступных типов полей; полный список можно найти в Поля форм.
Виджеты
У каждого поля формы есть соответствующий класс виджета, который, в свою очередь, соответствует HTML-виджету формы, например <input
type="text">.
В большинстве случаев у поля будет разумный виджет по умолчанию. Например, по умолчанию у CharField будет виджет TextInput, который создаёт <input type="text"> в HTML. Если вам нужно <textarea> вместо этого, вы укажете соответствующий виджет при определении поля формы, как мы сделали для поля message.
Данные поля
Какие бы данные ни были отправлены с формой, после успешной проверки с помощью вызова is_valid() (и is_valid() вернул True), данные проверенной формы будут в словаре form.cleaned_data. Эти данные будут корректно преобразованы в типы Python.
Примечание
Вы по-прежнему можете получить доступ к невалидированным данным напрямую из request.POST на этом этапе, но данные валидации лучше.
В примере формы контактов выше, cc_myself будет булевым значением. Аналогично, такие поля, как IntegerField и FloatField преобразуют значения в Python int и float соответственно.
Вот как данные формы могут быть обработаны в представлении, обрабатывающем эту форму:
from django.core.mail import send_mail
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['info@example.com']
if cc_myself:
recipients.append(sender)
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/')
Подсказка
Для получения дополнительной информации об отправке электронной почты из Django, см. Отправка электронной почты.
Некоторые типы полей требуют дополнительной обработки. Например, файлы, загруженные с помощью формы, необходимо обрабатывать по-другому (их можно получить из request.FILES, а не из request.POST). Для получения подробностей о том, как обрабатывать загрузки файлов с помощью формы, см. Связывание загруженных файлов с формой.
Работа с шаблонами форм
Для того, чтобы добавить вашу форму в шаблон, достаточно поместить экземпляр формы в контекст шаблона. Таким образом, если ваша форма называется form в контексте, {{ form }} будет правильно отображать её <label> и <input> элементы.
Параметры отображения формы
Дополнительные элементы шаблона формы
Не забудьте, что вывод формы не включает окружающие <form> теги или элемент управления формы submit. Вы должны предоставить их самостоятельно.
Однако существуют другие параметры вывода для пар <label>/<input>. Например:
-
{{ form.as_table }}будут отображаться как ячейки таблицы, заключенные в теги<tr> -
{{ form.as_p }}будут отображаться, заключенные в теги<p> -
{{ form.as_ul }}будут отображаться, заключенные в теги<li>
Обратите внимание, что вы должны сами предоставить окружающие элементы <table> или <ul>.
Вот вывод {{ form.as_p }} для нашего экземпляра ContactForm.
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label>
<textarea name="message" id="id_message" required></textarea></p>
<p><label for="id_sender">Sender:</label>
<input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself"></p>
Обратите внимание, что каждое поле формы имеет атрибут ID, установленный в id_<field-name>, на который ссылается сопровождающий тег метки. Это важно для обеспечения доступности форм для вспомогательных технологий, таких как программы для чтения с экрана. Вы также можете настроить способ генерации меток и идентификаторов.
См. Вывод форм в формате HTML для получения более подробной информации.
Отображение полей вручную
Мы не обязаны позволять Django распаковывать поля формы; мы можем сделать это вручную, если захотим (например, переупорядочив поля). Каждое поле доступно как атрибут формы с помощью {{ form.name_of_field }}, и в шаблоне Django будет отображаться соответствующим образом. Например:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>
Полные <label> элементы также можно сгенерировать с помощью label_tag(). Например:
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
Отображение сообщений об ошибках формы
Цена этой гибкости — немного больше работы. До сих пор нам не приходилось беспокоиться о том, как отображать ошибки формы, потому что это было сделано за нас. В этом примере нам пришлось убедиться, что мы обрабатываем любые ошибки для каждого поля и любые ошибки для всей формы в целом. Обратите внимание на {{ form.non_field_errors }} в верхней части формы и поиск шаблона для ошибок каждого поля.
Использование {{ form.name_of_field.errors }} отображает список ошибок формы, отформатированный как список без маркировки. Это может выглядеть так:
<ul class="errorlist">
<li>Sender is required.</li>
</ul>
Список имеет CSS-класс errorlist, чтобы вы могли стилизовать его внешний вид. Если вы хотите дополнительно настроить отображение ошибок, вы можете сделать это, перебирая их:
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
Ошибки, не относящиеся к полям (и/или ошибки скрытых полей, которые отображаются в верхней части формы при использовании вспомогательных средств, таких как form.as_p()), будут отображаться с дополнительным классом nonfield, чтобы отличить их от ошибок, специфичных для полей. Например, {{ form.non_field_errors }} будет выглядеть так:
<ul class="errorlist nonfield">
<li>Generic validation error</li>
</ul>
См. API форм для получения дополнительной информации об ошибках, стилях и работе с атрибутами форм в шаблонах.
Перебор полей формы
Если вы используете один и тот же HTML для каждого поля формы, вы можете сократить дублирование кода, перебирая каждое поле по очереди, используя цикл {% for %}:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
Полезные атрибуты {{ field }} включают:
-
{{ field.label }} - Метка поля, например,
Email address. -
{{ field.label_tag }} -
Метка поля, заключенная в соответствующий HTML
<label>тег. Это включаетlabel_suffixсуффикс метки формы. Например, по умолчаниюlabel_suffixэто двоеточие:<label for="id_email">Email address:</label>
-
{{ field.id_for_label }} - Идентификатор, который будет использоваться для этого поля (
id_emailв примере выше). Если вы создаёте метку вручную, вы можете использовать это вместоlabel_tag. Это также полезно, например, если у вас есть какой-то встроенный JavaScript и вы хотите избежать жёсткого кодирования идентификатора поля. -
{{ field.value }} - Значение поля. Например,
someone@example.com. -
{{ field.html_name }} - Имя поля, которое будет использоваться в поле имени элемента ввода. Это учитывает префикс формы, если он установлен.
-
{{ field.help_text }} - Любой текст справки, связанный с полем.
-
{{ field.errors }} - Выводит
<ul class="errorlist">, содержащий любые ошибки проверки, соответствующие этому полю. Вы можете настроить представление ошибок с помощью цикла{% for error in field.errors %}. В этом случае каждый объект в цикле — строка, содержащая сообщение об ошибке. -
{{ field.is_hidden }} - Этот атрибут
Trueесли поле формы — скрытое поле иFalseв противном случае. Он не особенно полезен как переменная шаблона, но может быть полезен в условных проверках, таких как:
{% if field.is_hidden %}
{# Do something special #}
{% endif %}
-
{{ field.field }} - Экземпляр
Fieldиз класса формы, который оборачивает этуBoundField. Вы можете использовать его для доступа к атрибутамField, например,{{ char_field.field.max_length }}.
См. также
Для получения полного списка атрибутов и методов см. BoundField.
Перебор скрытых и видимых полей
Django предоставляет два метода для формы, которые позволяют перебирать скрытые и видимые поля независимо: hidden_fields() и visible_fields(). Вот изменение предыдущего примера, использующее эти два метода:
{# Include the hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# Include the visible fields #}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
В этом примере не обрабатываются какие-либо ошибки в скрытых полях. Обычно ошибка в скрытом поле указывает на вмешательство в форму, так как нормальное взаимодействие с формой не изменяет их. Однако вы могли бы легко добавить отображение ошибок для этих ошибок формы.
Многократно используемые шаблоны форм
Если ваш сайт использует одинаковую логику отображения форм в нескольких местах, вы можете уменьшить дублирование, сохранив цикл формы в автономном шаблоне и используя тег include для его повторного использования в других шаблонах:
# In your form template:
{% include "form_snippet.html" %}
# In form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
Если объект формы, передаваемый шаблону, имеет другое имя в контексте, вы можете переименовать его с помощью аргумента with тега include:
{% include "form_snippet.html" with form=comment_form %}
Если вы часто делаете это, рассмотрите возможность создания пользовательского тега включения.
Дополнительные темы
Это базовые знания, но формы могут делать гораздо больше.
-
Наборы форм
- Использование начальных данных с набором форм
- Ограничение максимального количества форм
- Ограничение максимального количества экземпляризированных форм
- Валидация набора форм
- Валидация количества форм в наборе форм
- Обработка порядка и удаления форм
- Добавление дополнительных полей в набор форм
- Передача пользовательских параметров формам набора форм
- Настройка префикса набора форм
- Использование набора форм в представлениях и шаблонах
- Создание форм из моделей
-
Активы форм (класс
Media)
См. также
- Справочник по формам
- Охватывает полную справочную информацию по API, включая поля форм, виджеты форм и валидацию форм и полей.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.2/topics/forms/index/