Джанго руководство на русском

Все, что нужно знать о Django.

Как организована документация¶

У Джанго много документации. Общий обзор того, как она организована, поможет вам узнать, где искать необходимое:

  • Руководства. Пройдите серию шагов по созданию веб-приложения. Начните с них, если вы новичок в Django или разработке веб-приложений. Также посмотрите «Первые шаги» ниже.
  • Руководства объясняют ключевые темы и концепции на достаточно высоком уровне и предоставляют полезную справочную информацию и пояснения.
  • Справочные руководства содержат техническую информацию по API и другим аспектам работы Django. Они описывают, как всё работает и как это использовать, но предполагают, что у вас есть базовое понимание ключевых понятий.
  • Практические руководства являются рецептами. Они проведут вас через шаги, связанные с решением ключевых проблем и вариантов использования Django. Они более продвинуты, чем учебные пособия, и предполагают, что вы знаете как Django работает.

Производительность и оптимизация¶

Существует множество методик и инструментов, которые могут помочь сделать ваш код более эффективным — более быстрым и использующим меньше системных ресурсов.

  • Обзор производительности и оптимизации

Географический фреймворк¶

GeoDjango намеревается стать географическим веб-фреймворком мирового класса. Его цель — максимально упростить создание веб-приложений ГИС и использование возможностей пространственных данных.

Последнее обновление: 29.04.2023

Содержание руководства по созданию веб-приложений на языке Python с помощью фреймворка Django.

  1. Глава 1. Введение в Django

    1. Что такое Django

    2. Установка и настройка Django

    3. Создание первого проекта

    4. Создание первого приложения

  2. Глава 2. Представления и маршрутизация

    1. Обработка запроса

    2. Определение маршрутов и функции path и re_path

    3. Получение данных запроса. HttpRequest

    4. HttpResponse и отправка ответа

    5. Параметры представлений

    6. Вложенные маршруты и функция include

    7. Параметры строки запроса

    8. Переадресация и отправка статусных кодов

    9. Отправка json

    10. Отправка и получение кук

  3. Глава 3. Шаблоны

    1. Создание и использование шаблонов

    2. Передача данных в шаблоны

    3. Встроенные теги шаблонов

    4. Фильтры шаблонов

    5. Статические файлы

    6. TemplateView

    7. Конфигурация шаблонов

    8. Расширение шаблонов и фильтр extends

    9. Вложенные шаблоны и фильтр include

  4. Глава 4. Работа с формами

    1. Отправка форм

    2. Определение форм Django

    3. Типы полей формы

    4. Настройка формы и ее полей

    5. Валидация данных

    6. Детальная настройка полей формы

    7. Стилизация полей форм

  5. Глава 5. Модели

    1. Подключение к базе данных

    2. Создание моделей

    3. Типы полей моделей

    4. QuerySet API

    5. Создание и получение объектов модели

    6. Редактирование и удаление объектов модели

    7. Фильтрация

    8. values и values_list и сортировка

    9. Операции с множествами

    10. Получение отдельных объектов и проверка их наличия

    11. Агрегатные операции

    12. Выполнение SQL-выражений

    13. CRUD. Все базовые операции с моделями в веб-приложении

    14. Отношение один ко многим (One to Many)

    15. Практический пример связи один ко многим

    16. Отношение многие ко многим (Many to Many)

    17. Отношение многие ко многим (Many to Many)

    18. Отношение один к одному (One to one)

Время на прочтение
14 мин

Количество просмотров 288K

Представляю вам перевод статей о Django с сайта effectivedjango.com. Наткнулся я на этот сайт во время изучения данного фреймворка. Информация размещенная на этом ресурсе показалась мне полезной, но так как нигде не нашел перевода на русский, решил сделать сие доброе дело сам. Этот цикл статей, как мне думается, будет полезен веб-разработчикам, которые делают только первые шаги в изучении Django.


Оглавление

  • Введение
  • Эффективный Django. Руководство
    • Глава 1. Приступая к работе
    • Глава 2. Используем модель
    • Глава 3. Пишем представление
    • Глава 4. Используем статические ресурсы
    • Глава 5. Дополнительные базовые представления
    • Глава 6. Основы форм
    • Глава 7. Связанные модели
    • Глава 8. Обработка аутентификации и авторизации
  • Тестирование в Django
  • Понимание Middleware’ов
  • Базы данных и модели
  • Представления-классы (CBV)
  • Формы

Введение ⇧

Django — это популярный, мощный фреймворк на языке Python. Он имеет множество «батареек«, и позволяет сразу начать разработку. Однако вся эта мощь означает, что вы можете написать низкопробный код, который будет казаться рабочим. Так что же подразумевается под Эффективным Django? Под Эффективным Django будем понимать использование Django таким образом, чтобы написанный код был связным, тестируемым и масштабируемым. Что же каждое из этих слов значит?

«Связный» код — это код, который сосредоточен на выполнении одной вещи, только одной единственной вещи. Это значит, что когда вы пишете функцию или метод — написанный вами код должен делать что-то одно и делать это хорошо.

Это непосредственно относится к написанию тестируемого кода: код, который делает много вещей, достаточно часто является чересчур сложным для тестирования. Когда я ловлю себя на мысли: «Хорошо, этот кусок кода слишком сложен, чтобы писать для него тесты — это просто не стоит потраченных усилий» — вот сигнал к тому, чтобы вернутся назад и сосредоточиться на упрощении. Тестируемый код — такой код, который позволяет просто писать для него тесты; код, в котором легко найти проблемы.

И наконец, мы хотим писать масштабируемый код. Это означает не просто масштабировать его в терминах исполнения, но так же увеличивать в терминах команды и командного понимания. Хорошо протестированные приложения проще для понимания другими (и проще для изменения ими), что подразумевает большую возможность улучшить ваше приложение, путем добавления новых инженеров.

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

Эти документы являются сочетанием заметок и примеров подготовленных для PyCon 2012, PyOhio 2012, и PyCon 2013, а также для web-разработки Eventbrite. Я все еще работаю над объединением их в один документ, но надеюсь вы найдете их полезными.

Примеры кода для этого руководства доступны на github’е. Отзывы, предложения и вопросы можете присылать на nathan@yergler.net.
Этот документ доступен на сайте, а также в форматах PDF и EPub.

Видео этого руководства с PyCon можно посмотреть на YouTube.

Глава 1. Приступая к работе ⇧

1.1. Ваша среда разработки

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

Изоляция

означает, что вы не сможете случайно воспользоватся инструментами или пакетами установленными вне вашего окружения. Это особенно важно, когда подобное происходит с чем-то, похожим на пакеты Python с расширениями написанными на C: если вы используете что-то установленное на системном уровне и не знаете об этом, то при развертывании или распространении своего кода вы можете обнаружить, что он работает не так как предполагалось. Инструменты наподобие virtualenv могут помочь создать нечто похожее на изолированную среду.

Ваша среда

предопределена

, если вы уверены в том, на какую версию ваших зависимостей вы полагаетесь и сможете ли вы наверняка воспроизвести системное окружение.

И на конец,

сходство

с производственной средой или средой сервера разработки означает, что везде установлена одна и та же операционная система (возможно даже одинаковый выпуск) и вы используете одинаковые инструменты как для конфигурирования вашей среды разработки, так и для конфигурирования вашей производственной среды. Это отнюдь не необходимость, но если вы строите большое и сложное программное обеспечение — сходство будет полезно для уверенности в том, что все проблемы, которые вы можете увидеть на «боевом» сервере, воспроизводимы в той среде, где вы ведете разработку. К тому же

сходство

ограничивает область исследования вашего кода.

1.1.1. Изоляция

  • Мы хотим избежать использования неизвестных зависимостей или неизвестных версий.
  • virtualenv предоставляет простой путь для работы над проектом, без использования системных site-packages.

1.1.2. Предопределенность

  • Предопределенность означает управление зависимостями.
  • Выберете один из инструментов и используйте как при разработке, так на «боевом» сервере:
    • pip и специальные файлы зависимостей;
    • buildout;
    • install-requires в setup.py.
  • Определите точные версии зависимостей.

Вы можете точно определить версии используя либо версию пакета на PyPI, либо же определенную ревизию (SHA в git, номер ревизии в Subversion и т. д.). Это гарантирует вам возможность получить в точности те же версии пакетов, которые вы используете при тестировании.

1.1.3. Сходство

  • Работа в среде, похожей на ту, где вы будете разворачивать ваше приложение и пытаться обнаружить проблемы.
  • Если вы разрабатываете что-то, требующее дополнительных сервисов — сходство становится еще более важным.
  • Vagrant — это инструмент для управления виртуальными машинами, позволяющий вам легко создавать окружение отделенное от вашего повседневного окружения.

1.2. Настройка вашего окружения

1.2.1. Создание чистого рабочего пространства

Примечание переводчика:
Для начала создадим каталог (tutorial), в котором будем работать:

~$ mkdir tutorial
~$ cd tutorial
~/tutorial$ mkdir venv project

В каталоге venv будет находится наше виртуальное окружение, а в каталоге project — Django-проект

~/tutorial$ virtualenv --prompt="(venv:tutorial)" ./venv/

New python executable in ./venv/bin/python
Installing setuptools............done.
Installing pip...............done.

~/tutorial$ source ./venv/bin/activate
(venv:tutorial)~/tutorial$

1.2.2. Создание файла зависимостей

Создайте файл requirements.txt в директории tutorial с единственной строкой (зависимостью) в нем:

Django==1.6.7

Примечание переводчика:
В случае, если вы хотите использовать последнюю версию Django (1.7 — на момент написания перевода) — вместо строки Django==1.6.7 оставьте просто Django — pip установит последнюю доступную версию.

1.2.3. Установка зависимостей

А теперь мы можем использовать pip для установки зависимостей:

(venv:tutorial)~/tutorial$ pip install -U -r requirements.txt

Downloadping/unpacking Django==1.6.7 (from -r requirements.txt (line 1))
  Downloading Django-1.6.7.tar.gz (6.6MB): 6.6MB downloaded
  Running setup.py egg_info for package Django

    warning: no previously-included files matching ’__pycache__’ found under directory ’*’
    warning: no previously-included files matching ’*.py[co]’ found under directory ’*’
Installing collected packages: Django
  Running setup.py install for Django
    changing mode of build/scripts-2.7/django-admin.py from 644 to 755

    warning: no previously-included files matching ’__pycache__’ found under directory ’*’
    warning: no previously-included files matching ’*.py[co]’ found under directory ’*’
    changing mode of /home/nathan/p/edt/bin/django-admin.py to 755
Successfully installed Django
Cleaning up...

1.3. Начало проекта Django

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

Django, как и многие web-фреймворки, представляет скаффолдинг для вашей разработки. Это происходит при помощи принятия решений и предоставления отправной точки для вашего кода, что позволяет вам сосредоточится на проблеме, которую вы пытаетесь решить, а не на том, как разобрать HTTP-запрос. Django предоставляет скаффолдинг как для работы с HTTP, так и для работы с файловой системой.

HTTP-скаффолдинг управляет, например, преобразованием HTTP-запроса в объект языка Python, а также предоставляет инструменты для более простого создания серверных ответов. Скаффолдинг файловой системы иной: это набор соглашений по организации вашего кода. Эти соглашения облегчают добавление новых инженеров в проект, так как инженеры (гипотетически) уже понимают как организован код. В терминах Django, проект — это конечный продукт, и он объединяет внутри себя одно или несколько приложений. В Django 1.4 было изменено то, как проекты и приложения размещаются на диске, что облегчило разъединение и повторное использование приложений в разных проектах.

1.3.1. Создание проекта

Django устанавливает в систему скрипт django-admin.py для обработки задач скаффолдинга. Для создания файлов проекта используется задача startproject. Мы определим имя проекта и имя директории, в которой хотим разместить проект. Так как, мы уже находимся в изолированной среде, можно просто написать:

Примечание переводчика:
Перейдем директорию ~/tutorial/project/ и в дальнейшем будем работать только из этой директории (под $ далее будем подразумевать ~/tutorial/project/$):

(venv:tutorial)~/tutorial/$ cd project

(venv:tutorial)$ django-admin.py startproject addressbook .

Созданный проект имеет следующую структуру

manage.py
./addressbook
    __init__.py
    settings.py
    urls.py
    wsgi.py

1.3.2. Скаффолдинг проекта

  • manage.py — является ссылкой на скрипт django-admin, но с уже предустановленными переменными окружения, указывающими на ваш проект, как для чтения настроек оттуда, так и для управления им при необходимости;
  • settings.py — здесь находятся настройки вашего проекта. Файл уже содержит несколько разумных настроек, но база данных не указана;
  • urls.py — содержит URL’ы для маппирования (отображения) представлений: мы вскоре (в дальнейших главах) поговорим об этом подробнее;
  • wsgi.py — это WSGI обёртка для вашего приложения. Этот файл используется сервером разработки Django и возможно другими контейнерами, такими как mod_wsgi, uwsgi и др. на «боевом» сервере.

1.3.3. Создание приложения

(venv:tutorial)$ python ./manage.py startapp contacts

Созданное приложение имеет следующую структуру:

./contacts
    __init__.py
    models.py
    tests.py
    views.py

  • Начиная с Django 1.4, приложения размещаются внутри пакета с проектом. Это замечательное улучшение, особенно когда приходит время разворачивать проект на «боевом» сервере;
  • models.py будет содержать Django ORM-модели для вашего приложения;
  • views.py будет содержать код представлений;
  • tests.py будет содержать написанные вами модульные и интеграционные тесты.
  • Django 1.7: admin.py будет содержать модель для административного интерфейса.
  • Django 1.7: migrations/ содержит файлы миграций

Примечание переводчика:
На текущий момент наша директория ~/tutorial/ содержит файл зависимостей (requirements.txt), директорию с виртуальным окружением (venv/), один проект (project/addressbook), одно приложение (project/contacts) и имеет следующее содержание:

~/tutorial/
	requirements.txt
	venv/
		...
	project/
		manage.py
		addressbook/
			__init__.py
			settings.py
			urls.py
			wsgi.py
		contacts/
			__init__.py
			models.py
			tests.py
			views.py

Глава 2. Используем модель ⇧

2.1. Конфигурирование базы данных

Django поддерживает «из коробки» MySQL, PostgreSQL, SQLite3 и Oracle. SQLite3 входит в состав Python начиная с версии 2.5, так что мы будем использовать его в нашем проекте (для простоты). Если вы хотите, к примеру, использовать MySQL, то нужно добавить mysql-python в ваш requirements.txt.

Для того чтобы в качестве базы данных использовать SQLite, отредактируйте определение DATABASES в файле addressbook/settings.py. Файл settings.py содержит настройки Django для нашего проекта. В нем есть несколько настроек, которые вы обязаны указать — например DATABASES — а так же другие, необязательные, настройки. Django устанавливает некоторые настройки сам, когда генерирует проект. Документация содержит полный список настроек. К тому же вы можете добавить свои собственные настройки, если это необходимо.

Для использования SQLite нам нужно указать движок (ENGINE) и имя базы (NAME). SQLite интерпертирует имя базы как имя файла для базы данных:

DATABASES = {
    'defaults': {
	    'ENGINE': 'django.db.backends.sqlite3,' # ’postgresql_psycopg2’, ’mysql’, ’sqlite3’ or ’oracle'.
		'NAME': os.path.join(BASE_DIR, 'address.db'),
		'USER': '',     # Not used with sqlite3.
		'PASSWORD': '', # Not used with sqlite3.
		'HOST': '',     # Set to empty string for localhost. Not used with sqlite3.
		'PORT': '',     # Set to empty string for default. Not used with sqlite3.
	}
}

Заметьте, что движок базы данных указан строкой, а не прямой ссылкой на объект Python. Это сделано по той причине, что файл настроек должен быть легко импортирован не вызывая сторонних эффектов. Вы должны избегать добавления вызовов import в этот файл.

Вам редко придется непосредственно импортировать файл настроек: Django импортирует его за вас, и делает настройки доступными как django.conf.settings. Вы, как правило, импортируете настройки из django.conf:

from django.conf import settings

2.2. Создание модели

Модели Django отображают (грубо говоря) таблицы базы данных, и предоставляют место для инкапсулирования бизнес-логики. Все модели являются наследниками базового класса Model и содержат поля определений. Давайте создадим простую модель Contacts для нашего приложения в файле contacts/models.py:

from django.db import models

class Contact(models.Model):

    first_name = models.CharField(
        max_length=255,
    )
    last_name = models.CharField(
        max_length=255,
    )
	
    email = models.EmailField()

	def __str__(self):

	    return ' '.join([
            self.first_name,
            self.last_name,
        ])

Django предоставляет набор полей для отображения типов данных и различных правил валидации. К примеру, EmailField, который мы использовали, является отображением на колонку с типом CharField, но добавляет валидацию данных.

После того, как вы создали модель, необходимо дополнить вашу базу данных новыми таблицами. Команда Django syncdb смотрит установленные модели и создает (если нужно) таблицы для них:

Примечание переводчика:
Django предложит создать суперпользователя для андминки, которая включена в этой версии по умолчанию. Воспользуйтесь его предложением.

Примечание переводчика:
С версии Django 1.7 во фреймворк добавлена нативная поддержка миграций и команда syncdb объявлена устаревшей. Так что будьте так любезны, воспользуйтесь командой migrate вместо syncdb.

(venv:tutorial)$ python ./manage.py syncdb

Creating tables ...
Creating table django_admin_log
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use 'bjakushka'):
Email address: 
Password:
Password (again):
Superuser created successfully.
Installing custom SQL ...
installing indexes ...
Installed 0 object(s) from 0 fixture(s)

(venv:tutorial)$

Примечание переводчика:
Если вы используете Django версии 1.7 и выше — вывод будет следующий:

(venv:tutorial)$ python ./manage.py migrate

Opperation to perform:
    Apply all migrations: admin, contenttypes, auth, sessions
Running migrations:
    Applying contenttypes.0001_initial... OK
    Applying auth.0001_initial... OK
    Applying admin.0001_initial... OK
    Applying sessions.0001_initial... OK

(venv:tutorial)$ 

Однако нашей таблицы с контактами нигде не видно. Причина этого состоит в том, что нам нужно еще указать проекту использовать приложение.

Настройка INSTALLED_APPS содержит список приложений, используемых в проекте. Этот список содержит в себе строки, которые отображают пакеты Python. Django будет импортировать каждый из указанных пакетов, а потом смотреть модуль models. Давайте добавим наше приложение contacts в настройки проекта (addressbook/settings.py):

INSTALLED_APPS = (
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
  
  'contacts',
)

После этого запустите syncdb снова:

Примечание переводчика:
Для Django версии 1.7 и выше вам нужно будет запустить сначала команду makemigrations — для создания миграций на основе изменений в моделях, а после этого выполнить команду migrate — для того чтобы применить созданные миграции.

(venv:tutorial)$ python ./manage.py syncdb

Creating tables ...
Creating table contacts_contact
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

(venv:tutorial)$

Примечание переводчика:
Вывод для Django 1.7 и выше:

(venv:tutorial)$ python ./manage.py makemigrations

Migrations for 'contacts':
    0001_initial.py:
        - Create model Contact

(venv:tutorial)$ python ./manage.py migrate

Opperation to perform:
    Apply all migrations: admin, contenttypes, sessions, auth, contacts
Running migrations:
    Applying contacts.0001_initial... OK

(venv:tutorial)$ 

Заметьте, что Django создает таблицу с именем contacts_contact: по умолчанию Dj ango дает таблицам имена используя комбинацию имени приложения и имени модели. Вы можете изменить это с помощью опций модели Meta.

2.3. Взаимодействие с моделью

Теперь, когда модель синхронизирована с базой данных мы можем взаимодействовать с нею используя интерактивную оболочку:

(venv:tutorial)$ python ./manage.py shell
Python 2.7.3 (default, Mar 14 2014, 11:57:14)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from contacts.models import Contact
>>> Contact.objects.all()
[]
>>> Contact.objects.create(first_name='Nathan', last_name='Yergler')
<Contact: Nathan Yergler>
>>> Contact.objects.all()
[<Contact: Nathan Yergler>]
>>> nathan = Contact.objects.get(first_name='Nathan')
>>> nathan
<Contact: Nathan Yergler>
>>> print nathan
Nathan Yergler
>>> nathan.id
1

Здесь использовалось несколько новых штук. Во-первых, команда manage.py shell запускает для нас интерактивную оболочку Python’а с правильно установленными путями для Django. Если вы попробуете запустить интерпретатор Python и просто импортировать ваше приложения, будет выброшено исключение, потому что Django не знает, какие настройки использовать, и не может отобразить экземпляры модели на базу данных.

Во-вторых, здесь использовалось свойство objects нашей модели. Это менеджер модели. Так, если один экземпляр модели является аналогией для строки в базе, то менеджер модели — аналогией для таблицы. По умолчанию менеджер модели предоставляет функциональность запросов и может быть настроен. Когда мы вызываем all(), filter() или сам менеджер, возвращается объект QuerySet. QuerySet является итерируемым объектом и загружает данные из базы по необходимости.

И последнее — выше использовалось поле с именем id, которое мы не определяли в нашей модели. Django добавляет это поле как первичный ключ для модели, но только в том случае если вы сами не определили какое поле будет первичным ключом.

2.4. Написание тестов

В нашей модели определен один метод, __str__, так что настало время писать тесты. Метод __str__ будет использоваться всего лишь в нескольких местах, и, вполне возможно, полностью будет показан конечному пользователю. Для этого метода стоит написать тест, пока мы понимаем как он работает. Django создал файл tests.py когда создавал приложение, так что мы добавим первый тест в этот файл, приложения contacts.

from django.test import TestCase

from contacts.models import Contact

class ContactTests(TestCase):
    """Contact model tests."""
	
    def test_str(self):
	
        contact = Contact(first_name='John', last_name='Smith')
        self.assertEquals(
            str(contact),
            'John Smith',
        )

Вы можете запустить тесты для вашего приложения используя команду manage.py test:

(venv:tutorial)$ python ./manage.py test

Если вы запустите это, то увидите что выполнилось около 420 тестов. Это удивляет, так как мы написали только один. Произошло это потому, что по умолчанию Django запускает тесты для всех установленных приложений. Когда вы добавляли приложение contacts в наш проект, то могли увидеть, что там по умолчанию были добавлены несколько встроенных приложений Django. Дополнительные 419 тестов были взяты оттуда.

Примечание переводчика:
В нашем случае (при использовании версии Django 1.6.7) предыдущий абзац несколько устарел: запустится только один тест — тот который мы создали. Вывод команды будет такой как указано ниже.

Если же вы захотите запустить тесты для определенного приложения — укажите имя приложения в команде:

(venv:tutorial)$ python manage.py test contacts

Creating test database for alias ’default’...
.
----------------------------------------------------------------------
Ran 1 tests in 0.001s

OK
Destroying test database for alias ’default’...

(venv:tutorial)$

Еще одна интересная вещь на заметку, прежде чем двигаться дальше — первая и последняя строка вывода: Creating test database и Destroying test database. Некоторым тестам необходим доступ к базе данных, и поскольку мы не хотим мешать тестовые данные с «реальными» (по разным причинам, не последней из которых является предопределенность), Django услужливо создает тестовую базу для нас, прежде чем запускать тесты. По существу, создается новая база данных, и потом запускается syncdb для нее. Если тестовый класс является потомком класса TestCase (как у нас), Django так же сбросит данные в значения по умолчанию после запуска каждого теста, так что изменения в одном из тестов не затронут другие.

2.5. Резюме

  • Модель определяет поля в таблице, и содержит бизнес-логику.
  • Команда syncdb создает таблицы в вашей базе данных из моделей. В Django версии 1.7 и выше вместо команды syncdb необходимо использовать сначала команду makemigrations — для создания миграций, а после этого команду migrate — для внесение изменений в базу.
  • Менеджер модели позволяет вам оперировать коллекциями экземпляров: запросы, создание и т. д..
  • Пишите модульные тесты для методов, которые вы добавили в модель.
  • Команда управления test запускает модульные тесты на выполнение.

Примечание переводчика:
Для того чтобы протестировать наше, пока еще пустое, приложение нужно выполнить следующую команду:

(venv:tutorial)$ python ./manage.py runserver 0.0.0.0:8080

Это запустит встроенный сервер, функционал которого любезно предоставляет нам Django. В параметрах после runserver указывается ip-адрес и порт, который будет слушаться работающим сервер. В нашем случае сервер будет принимать запросы от всех ip-адресов при обращении на 8080 порт.

Я использую для разработки домашний сервер с внутренним IP 192.168.1.51. Так что для того что-бы увидеть результат работы сервера разработки в браузере я захожу по адресу http://192.168.1.51:8080/. Вы же должны подставить адрес своего сервера.


Как думаете, нужно ли продолжать перевод остальных глав? Оказался ли перевод для Вас полезен?
Буду рад конструктивной критике в комментариях.
Об ошибках и неточностях перевода прошу сообщать в личном сообщении.

Использованное в начале поста изображение создано как вариация изображения пользователя MaGIc2laNTern


admin

  1. admin.AdminSite.add_action()
  2. admin.AdminSite.disable_action()
  3. admin.ModelAdmin.get_actions()
  4. admin.action()
  5. admin.AdminSite
  6. admin.AdminSite.app_index_template
  7. admin.AdminSite.each_context()
  8. admin.AdminSite.empty_value_display
  9. admin.AdminSite.enable_nav_sidebar
  10. admin.AdminSite.final_catch_all_view
  11. admin.AdminSite.get_app_list()
  12. admin.AdminSite.has_permission()
  13. admin.AdminSite.index_template
  14. admin.AdminSite.index_title
  15. admin.AdminSite.login_form
  16. admin.AdminSite.login_template
  17. admin.AdminSite.logout_template
  18. admin.AdminSite.password_change_done_template
  19. admin.AdminSite.password_change_template
  20. admin.AdminSite.register()
  21. admin.AdminSite.site_header
  22. admin.AdminSite.site_title
  23. admin.AdminSite.site_url
  24. admin.AdminSite.unregister()
  25. admin.InlineModelAdmin
  26. admin.InlineModelAdmin.can_delete
  27. admin.InlineModelAdmin.classes
  28. admin.InlineModelAdmin.extra
  29. admin.InlineModelAdmin.fk_name
  30. admin.InlineModelAdmin.form
  31. admin.InlineModelAdmin.formset
  32. admin.InlineModelAdmin.get_extra()
  33. admin.InlineModelAdmin.get_formset()
  34. admin.InlineModelAdmin.get_max_num()
  35. admin.InlineModelAdmin.get_min_num()
  36. admin.InlineModelAdmin.has_add_permission()
  37. admin.InlineModelAdmin.has_change_permission()
  38. admin.InlineModelAdmin.has_delete_permission()
  39. admin.InlineModelAdmin.max_num
  40. admin.InlineModelAdmin.min_num
  41. admin.InlineModelAdmin.model
  42. admin.InlineModelAdmin.raw_id_fields
  43. admin.InlineModelAdmin.show_change_link
  44. admin.InlineModelAdmin.template
  45. admin.InlineModelAdmin.verbose_name
  46. admin.InlineModelAdmin.verbose_name_plural
  47. admin.ModelAdmin
  48. admin.ModelAdmin.actions
  49. admin.ModelAdmin.actions_on_bottom
  50. admin.ModelAdmin.actions_on_top
  51. admin.ModelAdmin.actions_selection_counter
  52. admin.ModelAdmin.add_form_template
  53. admin.ModelAdmin.add_view()
  54. admin.ModelAdmin.autocomplete_fields
  55. admin.ModelAdmin.change_form_template
  56. admin.ModelAdmin.change_list_template
  57. admin.ModelAdmin.change_view()
  58. admin.ModelAdmin.changelist_view()
  59. admin.ModelAdmin.date_hierarchy
  60. admin.ModelAdmin.delete_confirmation_template
  61. admin.ModelAdmin.delete_model()
  62. admin.ModelAdmin.delete_queryset()
  63. admin.ModelAdmin.delete_selected_confirmation_template
  64. admin.ModelAdmin.delete_view()
  65. admin.ModelAdmin.empty_value_display
  66. admin.ModelAdmin.exclude
  67. admin.ModelAdmin.fields
  68. admin.ModelAdmin.fieldsets
  69. admin.ModelAdmin.filter_horizontal
  70. admin.ModelAdmin.filter_vertical
  71. admin.ModelAdmin.form
  72. admin.ModelAdmin.formfield_for_choice_field()
  73. admin.ModelAdmin.formfield_for_foreignkey()
  74. admin.ModelAdmin.formfield_for_manytomany()
  75. admin.ModelAdmin.formfield_overrides
  76. admin.ModelAdmin.get_autocomplete_fields()
  77. admin.ModelAdmin.get_changeform_initial_data()
  78. admin.ModelAdmin.get_changelist()
  79. admin.ModelAdmin.get_changelist_form()
  80. admin.ModelAdmin.get_changelist_formset()
  81. admin.ModelAdmin.get_deleted_objects()
  82. admin.ModelAdmin.get_exclude()
  83. admin.ModelAdmin.get_fields()
  84. admin.ModelAdmin.get_fieldsets()
  85. admin.ModelAdmin.get_form()
  86. admin.ModelAdmin.get_formset_kwargs()
  87. admin.ModelAdmin.get_formsets_with_inlines()
  88. admin.ModelAdmin.get_inline_instances()
  89. admin.ModelAdmin.get_inlines()
  90. admin.ModelAdmin.get_list_display()
  91. admin.ModelAdmin.get_list_display_links()
  92. admin.ModelAdmin.get_list_filter()
  93. admin.ModelAdmin.get_list_select_related()
  94. admin.ModelAdmin.get_ordering()
  95. admin.ModelAdmin.get_paginator()
  96. admin.ModelAdmin.get_prepopulated_fields()
  97. admin.ModelAdmin.get_queryset()
  98. admin.ModelAdmin.get_readonly_fields()
  99. admin.ModelAdmin.get_search_fields()
  100. admin.ModelAdmin.get_search_results()
  101. admin.ModelAdmin.get_sortable_by()
  102. admin.ModelAdmin.get_urls()
  103. admin.ModelAdmin.has_add_permission()
  104. admin.ModelAdmin.has_change_permission()
  105. admin.ModelAdmin.has_delete_permission()
  106. admin.ModelAdmin.has_module_permission()
  107. admin.ModelAdmin.has_view_permission()
  108. admin.ModelAdmin.history_view()
  109. admin.ModelAdmin.inlines
  110. admin.ModelAdmin.list_display
  111. admin.ModelAdmin.list_display_links
  112. admin.ModelAdmin.list_editable
  113. admin.ModelAdmin.list_filter
  114. admin.ModelAdmin.list_max_show_all
  115. admin.ModelAdmin.list_per_page
  116. admin.ModelAdmin.list_select_related
  117. admin.ModelAdmin.lookup_allowed()
  118. admin.ModelAdmin.message_user()
  119. admin.ModelAdmin.object_history_template
  120. admin.ModelAdmin.ordering
  121. admin.ModelAdmin.paginator
  122. admin.ModelAdmin.popup_response_template
  123. admin.ModelAdmin.prepopulated_fields
  124. admin.ModelAdmin.preserve_filters
  125. admin.ModelAdmin.radio_fields
  126. admin.ModelAdmin.raw_id_fields
  127. admin.ModelAdmin.readonly_fields
  128. admin.ModelAdmin.response_add()
  129. admin.ModelAdmin.response_change()
  130. admin.ModelAdmin.response_delete()
  131. admin.ModelAdmin.save_as
  132. admin.ModelAdmin.save_as_continue
  133. admin.ModelAdmin.save_formset()
  134. admin.ModelAdmin.save_model()
  135. admin.ModelAdmin.save_on_top
  136. admin.ModelAdmin.save_related()
  137. admin.ModelAdmin.search_fields
  138. admin.ModelAdmin.search_help_text
  139. admin.ModelAdmin.show_full_result_count
  140. admin.ModelAdmin.sortable_by
  141. admin.ModelAdmin.view_on_site
  142. admin.StackedInline
  143. admin.TabularInline
  144. admin.apps.AdminConfig
  145. admin.apps.SimpleAdminConfig
  146. admin.apps.SimpleAdminConfig.default_site
  147. admin.autodiscover()
  148. admin.display()
  149. admin.models.LogEntry
  150. admin.models.LogEntry.action_flag
  151. admin.models.LogEntry.action_time
  152. admin.models.LogEntry.change_message
  153. admin.models.LogEntry.content_type
  154. admin.models.LogEntry.get_change_message()
  155. admin.models.LogEntry.get_edited_object()
  156. admin.models.LogEntry.object_id
  157. admin.models.LogEntry.object_repr
  158. admin.models.LogEntry.user
  159. admin.register()
  160. admin.views.decorators.staff_member_required()

API

  1. Applications
  2. Фреймворк проверки системы
  3. Base views
  4. Общие представления о дате
  5. Общий вид дисплея
  6. Общие представления при редактировании
  7. Встроенный API представлений на основе классов
  8. Смеси представлений на основе классов
  9. Date-based mixins
  10. Editing mixins
  11. Многочисленные объектные микшины
  12. Simple mixins
  13. Однообъектные смеси
  14. Clickjacking Protection
  15. Admin actions
  16. Генератор документации администратора Django
  17. Фильтры списков ModelAdmin
  18. Сайт администратора Django
  19. Настройки JavaScript у администратора
  20. django.contrib.auth
  21. Структура контент-типов
  22. Приложение для плоских страниц
  23. сайт администратора GeoDjango
  24. Команды управления GeoDjango
  25. API базы данных GeoDjango
  26. Deploying GeoDjango
  27. Geographic Feeds
  28. GeoDjango Forms API
  29. Функции географической базы данных
  30. GDAL API
  31. Геолокация с GeoIP2
  32. Ссылка на API GIS QuerySet
  33. GEOS API
  34. GeoDjango
  35. Установка геопространственных библиотек
  36. GeoDjango Installation
  37. Installing PostGIS
  38. Installing SpatiaLite
  39. Утилита импорта данных LayerMapping
  40. Measurement Objects
  41. API модели GeoDjango
  42. OGR Inspection
  43. GeoJSON Serializer
  44. Geographic Sitemaps
  45. Тестирование приложений GeoDjango
  46. GeoDjango Tutorial
  47. GeoDjango Utilities
  48. django.contrib.humanize
  49. contrib packages
  50. Фреймворк сообщений
  51. Специфические функции агрегации PostgreSQL
  52. Ограничения конкретной базы данных PostgreSQL
  53. Выражения запросов,специфичные для PostgreSQL
  54. Поля конкретной модели PostgreSQL
  55. Поля конкретной формы PostgreSQL и виджеты
  56. Функции конкретной базы данных PostgreSQL
  57. django.contrib.postgres
  58. Индексы конкретной модели PostgreSQL
  59. Специфический поиск по PostgreSQL
  60. Миграционные операции Базы данных
  61. Полнотекстовый поиск
  62. Validators
  63. Приложение перенаправления
  64. Карта сайта
  65. Структура «сайты»
  66. Приложение статических файлов
  67. Система синдицированной подачи корма
  68. Защита от подделок при перекрестных запросах
  69. Databases
  70. django-admin and manage.py
  71. Django Exceptions
  72. Объект «Файл
  73. File handling
  74. API хранения файлов
  75. Загруженные файлы и обработчики загрузки
  76. Формы API
  77. Form fields
  78. Formset Functions
  79. Forms
  80. Форма модели Функции
  81. API рендеринга формы
  82. Проверка формы и поля
  83. Widgets
  84. API Reference
  85. Logging
  86. Middleware
  87. Migration Operations
  88. Ссылка на класс модели
  89. Conditional Expressions
  90. Constraints reference
  91. Database Functions
  92. Query Expressions
  93. Ссылка на модель поля
  94. Models
  95. Ссылка на индекс модели
  96. Ссылка на образец модели
  97. Ссылка на API поиска
  98. Модель _API цель
  99. Опции Модели Мета
  100. Ссылка на QuerySet API
  101. Ссылка на связанные объекты
  102. Paginator
  103. Объекты запроса и ответа
  104. SchemaEditor
  105. Settings
  106. Signals
  107. TemplateResponse и SimpleTemplateResponse
  108. Язык шаблонов Django:для программистов Python
  109. Встроенные теги и фильтры шаблонов
  110. Templates
  111. Язык шаблонов Django
  112. Unicode data
  113. функции утилиты django.urls
  114. функции django.urls для использования в URLconfs
  115. Django Utils
  116. Validators
  117. Built-in Views

apps

  1. apps.AppConfig
  2. apps.AppConfig.default
  3. apps.AppConfig.default_auto_field
  4. apps.AppConfig.get_model()
  5. apps.AppConfig.get_models()
  6. apps.AppConfig.label
  7. apps.AppConfig.models_module
  8. apps.AppConfig.module
  9. apps.AppConfig.name
  10. apps.AppConfig.path
  11. apps.AppConfig.ready()
  12. apps.AppConfig.verbose_name
  13. apps.apps
  14. apps.apps.get_app_config()
  15. apps.apps.get_app_configs()
  16. apps.apps.get_model()
  17. apps.apps.is_installed()
  18. apps.apps.ready

Guides

  1. Asynchronous support
  2. Настройка аутентификации в Django
  3. Использование системы аутентификации Django
  4. Аутентификация пользователей в Django
  5. Управление паролями в Django
  6. кэш-фреймворк Django
  7. Фреймворк проверки системы
  8. Встроенные классовые общие представления
  9. Обработка форм с помощью представлений на основе классов
  10. Class-based views
  11. Введение в классовые представления
  12. Использование смесей с классовыми представлениями
  13. Обработка условного просмотра
  14. Aggregation
  15. Примеры использования API модельного соотношения
  16. Many-to-many relationships
  17. Many-to-one relationships
  18. One-to-one relationships
  19. Модели и базы данных
  20. Database instrumentation
  21. Managers
  22. Models
  23. Multiple databases
  24. Оптимизация доступа к базе данных
  25. Making queries
  26. Search
  27. Выполнение сырых SQL-запросов
  28. Tablespaces
  29. Database transactions
  30. Sending email
  31. External packages
  32. Managing files
  33. Formsets
  34. Работа с формами
  35. Форма Активы (класс носителя)
  36. Создание форм из моделей
  37. View decorators
  38. File Uploads
  39. Generic views
  40. Обработка HTTP-запросов
  41. Middleware
  42. Как использовать сеансы
  43. функции ярлыков Django
  44. URL dispatcher
  45. Writing views
  46. Format localization
  47. Интернационализация и локализация
  48. Time zones
  49. Translation
  50. Using Django
  51. Как установить Django
  52. Logging
  53. Migrations
  54. Pagination
  55. Производительность и оптимизация
  56. Безопасность в Джанго
  57. Сериализация объектов Django
  58. Django settings
  59. Signals
  60. Cryptographic signing
  61. Templates
  62. Расширенные темы тестирования
  63. Тестирование на Django
  64. Пишущий и выполняющий тесты
  65. Testing tools

auth

  1. auth.backends.AllowAllUsersModelBackend
  2. auth.backends.AllowAllUsersRemoteUserBackend
  3. auth.backends.BaseBackend
  4. auth.backends.BaseBackend.get_all_permissions()
  5. auth.backends.BaseBackend.get_group_permissions()
  6. auth.backends.BaseBackend.get_user_permissions()
  7. auth.backends.BaseBackend.has_perm()
  8. auth.backends.ModelBackend
  9. auth.backends.ModelBackend.authenticate()
  10. auth.backends.ModelBackend.get_all_permissions()
  11. auth.backends.ModelBackend.get_group_permissions()
  12. auth.backends.ModelBackend.get_user_permissions()
  13. auth.backends.ModelBackend.has_module_perms()
  14. auth.backends.ModelBackend.has_perm()
  15. auth.backends.ModelBackend.user_can_authenticate()
  16. auth.backends.ModelBackend.with_perm()
  17. auth.backends.RemoteUserBackend
  18. auth.backends.RemoteUserBackend.authenticate()
  19. auth.backends.RemoteUserBackend.clean_username()
  20. auth.backends.RemoteUserBackend.configure_user()
  21. auth.backends.RemoteUserBackend.create_unknown_user
  22. auth.backends.RemoteUserBackend.user_can_authenticate()
  23. auth.get_user()
  24. auth.models.AnonymousUser
  25. auth.models.Group
  26. auth.models.Group.name
  27. auth.models.Group.permissions
  28. auth.models.Permission
  29. auth.models.Permission.codename
  30. auth.models.Permission.content_type
  31. auth.models.Permission.name
  32. auth.models.User
  33. auth.models.User.check_password()
  34. auth.models.User.date_joined
  35. auth.models.User.email
  36. auth.models.User.email_user()
  37. auth.models.User.first_name
  38. auth.models.User.get_all_permissions()
  39. auth.models.User.get_full_name()
  40. auth.models.User.get_group_permissions()
  41. auth.models.User.get_short_name()
  42. auth.models.User.get_user_permissions()
  43. auth.models.User.get_username()
  44. auth.models.User.groups
  45. auth.models.User.has_module_perms()
  46. auth.models.User.has_perm()
  47. auth.models.User.has_perms()
  48. auth.models.User.has_usable_password()
  49. auth.models.User.is_active
  50. auth.models.User.is_anonymous
  51. auth.models.User.is_authenticated
  52. auth.models.User.is_staff
  53. auth.models.User.is_superuser
  54. auth.models.User.last_login
  55. auth.models.User.last_name
  56. auth.models.User.password
  57. auth.models.User.set_password()
  58. auth.models.User.set_unusable_password()
  59. auth.models.User.user_permissions
  60. auth.models.User.username
  61. auth.models.UserManager
  62. auth.models.UserManager.create_superuser()
  63. auth.models.UserManager.create_user()
  64. auth.models.UserManager.with_perm()
  65. auth.signals.user_logged_in
  66. auth.signals.user_logged_out
  67. auth.signals.user_login_failed
  68. auth.validators.ASCIIUsernameValidator
  69. auth.validators.UnicodeUsernameValidator
  70. auth.middleware.AuthenticationMiddleware
  71. auth.middleware.PersistentRemoteUserMiddleware
  72. auth.middleware.RemoteUserMiddleware
  73. auth.context_processors.auth()
  74. auth.get_user_model()
  75. auth.is_active
  76. auth.is_staff
  77. auth.models.AbstractBaseUser
  78. auth.models.AbstractBaseUser.check_password()
  79. auth.models.AbstractBaseUser.clean()
  80. auth.models.AbstractBaseUser.get_email_field_name()
  81. auth.models.AbstractBaseUser.get_session_auth_hash()
  82. auth.models.AbstractBaseUser.get_username()
  83. auth.models.AbstractBaseUser.has_usable_password()
  84. auth.models.AbstractBaseUser.is_anonymous
  85. auth.models.AbstractBaseUser.is_authenticated
  86. auth.models.AbstractBaseUser.normalize_username()
  87. auth.models.AbstractBaseUser.set_password()
  88. auth.models.AbstractBaseUser.set_unusable_password()
  89. auth.models.AbstractUser
  90. auth.models.AbstractUser.clean()
  91. auth.models.BaseUserManager
  92. auth.models.BaseUserManager.get_by_natural_key()
  93. auth.models.BaseUserManager.make_random_password()
  94. auth.models.BaseUserManager.normalize_email()
  95. auth.models.CustomUser
  96. auth.models.CustomUser.EMAIL_FIELD
  97. auth.models.CustomUser.REQUIRED_FIELDS
  98. auth.models.CustomUser.USERNAME_FIELD
  99. auth.models.CustomUser.get_full_name()
  100. auth.models.CustomUser.get_short_name()
  101. auth.models.CustomUser.is_active
  102. auth.models.CustomUserManager
  103. auth.models.CustomUserManager.create_superuser()
  104. auth.models.CustomUserManager.create_user()
  105. auth.models.PermissionsMixin
  106. auth.models.PermissionsMixin.get_all_permissions()
  107. auth.models.PermissionsMixin.get_group_permissions()
  108. auth.models.PermissionsMixin.get_user_permissions()
  109. auth.models.PermissionsMixin.has_module_perms()
  110. auth.models.PermissionsMixin.has_perm()
  111. auth.models.PermissionsMixin.has_perms()
  112. auth.models.PermissionsMixin.is_superuser
  113. auth.authenticate()
  114. auth.decorators.login_required()
  115. auth.decorators.permission_required()
  116. auth.decorators.user_passes_test()
  117. auth.forms.AdminPasswordChangeForm
  118. auth.forms.AuthenticationForm
  119. auth.forms.AuthenticationForm.confirm_login_allowed()
  120. auth.forms.PasswordChangeForm
  121. auth.forms.PasswordResetForm
  122. auth.forms.PasswordResetForm.send_mail()
  123. auth.forms.SetPasswordForm
  124. auth.forms.UserChangeForm
  125. auth.forms.UserCreationForm
  126. auth.login()
  127. auth.logout()
  128. auth.mixins.AccessMixin
  129. auth.mixins.AccessMixin.get_login_url()
  130. auth.mixins.AccessMixin.get_permission_denied_message()
  131. auth.mixins.AccessMixin.get_redirect_field_name()
  132. auth.mixins.AccessMixin.handle_no_permission()
  133. auth.mixins.AccessMixin.login_url
  134. auth.mixins.AccessMixin.permission_denied_message
  135. auth.mixins.AccessMixin.raise_exception
  136. auth.mixins.AccessMixin.redirect_field_name
  137. auth.mixins.LoginRequiredMixin
  138. auth.mixins.PermissionRequiredMixin
  139. auth.mixins.PermissionRequiredMixin.get_permission_required()
  140. auth.mixins.PermissionRequiredMixin.has_permission()
  141. auth.mixins.UserPassesTestMixin
  142. auth.mixins.UserPassesTestMixin.get_test_func()
  143. auth.mixins.UserPassesTestMixin.test_func()
  144. auth.update_session_auth_hash()
  145. auth.views.LoginView
  146. auth.views.LoginView.authentication_form
  147. auth.views.LoginView.extra_context
  148. auth.views.LoginView.get_default_redirect_url()
  149. auth.views.LoginView.next_page
  150. auth.views.LoginView.redirect_authenticated_user
  151. auth.views.LoginView.redirect_field_name
  152. auth.views.LoginView.success_url_allowed_hosts
  153. auth.views.LoginView.template_name
  154. auth.views.LogoutView
  155. auth.views.LogoutView.extra_context
  156. auth.views.LogoutView.next_page
  157. auth.views.LogoutView.redirect_field_name
  158. auth.views.LogoutView.success_url_allowed_hosts
  159. auth.views.LogoutView.template_name
  160. auth.views.PasswordChangeDoneView
  161. auth.views.PasswordChangeDoneView.extra_context
  162. auth.views.PasswordChangeDoneView.template_name
  163. auth.views.PasswordChangeView
  164. auth.views.PasswordChangeView.extra_context
  165. auth.views.PasswordChangeView.form_class
  166. auth.views.PasswordChangeView.success_url
  167. auth.views.PasswordChangeView.template_name
  168. auth.views.PasswordResetCompleteView
  169. auth.views.PasswordResetCompleteView.extra_context
  170. auth.views.PasswordResetCompleteView.template_name
  171. auth.views.PasswordResetConfirmView
  172. auth.views.PasswordResetConfirmView.extra_context
  173. auth.views.PasswordResetConfirmView.form_class
  174. auth.views.PasswordResetConfirmView.post_reset_login
  175. auth.views.PasswordResetConfirmView.post_reset_login_backend
  176. auth.views.PasswordResetConfirmView.reset_url_token
  177. auth.views.PasswordResetConfirmView.success_url
  178. auth.views.PasswordResetConfirmView.template_name
  179. auth.views.PasswordResetConfirmView.token_generator
  180. auth.views.PasswordResetDoneView
  181. auth.views.PasswordResetDoneView.extra_context
  182. auth.views.PasswordResetDoneView.template_name
  183. auth.views.PasswordResetView
  184. auth.views.PasswordResetView.email_template_name
  185. auth.views.PasswordResetView.extra_context
  186. auth.views.PasswordResetView.extra_email_context
  187. auth.views.PasswordResetView.form_class
  188. auth.views.PasswordResetView.from_email
  189. auth.views.PasswordResetView.html_email_template_name
  190. auth.views.PasswordResetView.subject_template_name
  191. auth.views.PasswordResetView.success_url
  192. auth.views.PasswordResetView.template_name
  193. auth.views.PasswordResetView.token_generator
  194. auth.views.logout_then_login()
  195. auth.views.redirect_to_login()
  196. auth.hashers.check_password()
  197. auth.hashers.is_password_usable()
  198. auth.hashers.make_password()
  199. auth.password_validation.CommonPasswordValidator
  200. auth.password_validation.MinimumLengthValidator
  201. auth.password_validation.NumericPasswordValidator
  202. auth.password_validation.UserAttributeSimilarityValidator
  203. auth.password_validation.get_password_validators()
  204. auth.password_validation.password_changed()
  205. auth.password_validation.password_validators_help_text_html()
  206. auth.password_validation.password_validators_help_texts()
  207. auth.password_validation.validate_password()

conf

  1. conf.urls.handler400
  2. conf.urls.handler403
  3. conf.urls.handler404
  4. conf.urls.handler500
  5. conf.urls.static.static()
  6. conf.urls.i18n.i18n_patterns()
  7. conf.settings.configure()
  8. conf.settings.configured

contenttypes

  1. contenttypes.admin.GenericInlineModelAdmin
  2. contenttypes.admin.GenericInlineModelAdmin.ct_field
  3. contenttypes.admin.GenericInlineModelAdmin.ct_fk_field
  4. contenttypes.admin.GenericStackedInline
  5. contenttypes.admin.GenericTabularInline
  6. contenttypes.fields.GenericForeignKey
  7. contenttypes.fields.GenericForeignKey.for_concrete_model
  8. contenttypes.fields.GenericRelation
  9. contenttypes.fields.GenericRelation.related_query_name
  10. contenttypes.forms.BaseGenericInlineFormSet
  11. contenttypes.forms.generic_inlineformset_factory()
  12. contenttypes.models.ContentType
  13. contenttypes.models.ContentType.app_label
  14. contenttypes.models.ContentType.get_object_for_this_type()
  15. contenttypes.models.ContentType.model
  16. contenttypes.models.ContentType.model_class()
  17. contenttypes.models.ContentType.name
  18. contenttypes.models.ContentTypeManager
  19. contenttypes.models.ContentTypeManager.clear_cache()
  20. contenttypes.models.ContentTypeManager.get_by_natural_key()
  21. contenttypes.models.ContentTypeManager.get_for_id()
  22. contenttypes.models.ContentTypeManager.get_for_model()
  23. contenttypes.models.ContentTypeManager.get_for_models()

core

  1. core.files.storage._open()
  2. core.files.storage._save()
  3. core.files.storage.get_alternative_name()
  4. core.files.storage.get_available_name()
  5. core.files.storage.get_valid_name()
  6. core.management.AppCommand
  7. core.management.AppCommand.handle_app_config()
  8. core.management.BaseCommand
  9. core.management.BaseCommand.add_arguments()
  10. core.management.BaseCommand.check()
  11. core.management.BaseCommand.create_parser()
  12. core.management.BaseCommand.execute()
  13. core.management.BaseCommand.get_version()
  14. core.management.BaseCommand.handle()
  15. core.management.BaseCommand.help
  16. core.management.BaseCommand.missing_args_message
  17. core.management.BaseCommand.output_transaction
  18. core.management.BaseCommand.requires_migrations_checks
  19. core.management.BaseCommand.requires_system_checks
  20. core.management.BaseCommand.style
  21. core.management.BaseCommand.suppressed_base_arguments
  22. core.management.LabelCommand
  23. core.management.LabelCommand.handle_label()
  24. core.management.LabelCommand.label
  25. core.checks.CheckMessage
  26. core.checks.Critical
  27. core.checks.Debug
  28. core.checks.Error
  29. core.checks.Info
  30. core.checks.Warning
  31. core.management.call_command()
  32. core.exceptions.NON_FIELD_ERRORS
  33. core.files.File
  34. core.files.File.__iter__()
  35. core.files.File.chunks()
  36. core.files.File.close()
  37. core.files.File.delete()
  38. core.files.File.file
  39. core.files.File.mode
  40. core.files.File.multiple_chunks()
  41. core.files.File.name
  42. core.files.File.open()
  43. core.files.File.save()
  44. core.files.File.size
  45. core.files.base.ContentFile
  46. core.files.images.ImageFile
  47. core.files.images.ImageFile.height
  48. core.files.images.ImageFile.width
  49. core.files.storage.DefaultStorage
  50. core.files.storage.FileSystemStorage
  51. core.files.storage.FileSystemStorage.base_url
  52. core.files.storage.FileSystemStorage.directory_permissions_mode
  53. core.files.storage.FileSystemStorage.file_permissions_mode
  54. core.files.storage.FileSystemStorage.get_created_time()
  55. core.files.storage.FileSystemStorage.location
  56. core.files.storage.Storage
  57. core.files.storage.Storage.delete()
  58. core.files.storage.Storage.exists()
  59. core.files.storage.Storage.generate_filename()
  60. core.files.storage.Storage.get_accessed_time()
  61. core.files.storage.Storage.get_alternative_name()
  62. core.files.storage.Storage.get_available_name()
  63. core.files.storage.Storage.get_created_time()
  64. core.files.storage.Storage.get_modified_time()
  65. core.files.storage.Storage.get_valid_name()
  66. core.files.storage.Storage.listdir()
  67. core.files.storage.Storage.open()
  68. core.files.storage.Storage.path()
  69. core.files.storage.Storage.save()
  70. core.files.storage.Storage.size()
  71. core.files.storage.Storage.url()
  72. core.files.storage.get_storage_class()
  73. core.files.uploadedfile.InMemoryUploadedFile
  74. core.files.uploadedfile.TemporaryUploadedFile
  75. core.files.uploadedfile.TemporaryUploadedFile.temporary_file_path()
  76. core.files.uploadedfile.UploadedFile
  77. core.files.uploadedfile.UploadedFile.charset
  78. core.files.uploadedfile.UploadedFile.chunks()
  79. core.files.uploadedfile.UploadedFile.content_type
  80. core.files.uploadedfile.UploadedFile.content_type_extra
  81. core.files.uploadedfile.UploadedFile.multiple_chunks()
  82. core.files.uploadedfile.UploadedFile.name
  83. core.files.uploadedfile.UploadedFile.read()
  84. core.files.uploadedfile.UploadedFile.size
  85. core.files.uploadhandler.FileUploadHandler
  86. core.files.uploadhandler.FileUploadHandler.chunk_size
  87. core.files.uploadhandler.FileUploadHandler.file_complete()
  88. core.files.uploadhandler.FileUploadHandler.handle_raw_input()
  89. core.files.uploadhandler.FileUploadHandler.new_file()
  90. core.files.uploadhandler.FileUploadHandler.receive_data_chunk()
  91. core.files.uploadhandler.FileUploadHandler.upload_complete()
  92. core.files.uploadhandler.FileUploadHandler.upload_interrupted()
  93. core.files.uploadhandler.MemoryFileUploadHandler
  94. core.files.uploadhandler.TemporaryFileUploadHandler
  95. core.paginator.Page
  96. core.paginator.Page.end_index()
  97. core.paginator.Page.has_next()
  98. core.paginator.Page.has_other_pages()
  99. core.paginator.Page.has_previous()
  100. core.paginator.Page.next_page_number()
  101. core.paginator.Page.number
  102. core.paginator.Page.object_list
  103. core.paginator.Page.paginator
  104. core.paginator.Page.previous_page_number()
  105. core.paginator.Page.start_index()
  106. core.paginator.Paginator
  107. core.paginator.Paginator.ELLIPSIS
  108. core.paginator.Paginator.allow_empty_first_page
  109. core.paginator.Paginator.count
  110. core.paginator.Paginator.get_elided_page_range()
  111. core.paginator.Paginator.get_page()
  112. core.paginator.Paginator.num_pages
  113. core.paginator.Paginator.object_list
  114. core.paginator.Paginator.orphans
  115. core.paginator.Paginator.page()
  116. core.paginator.Paginator.page_range
  117. core.paginator.Paginator.per_page
  118. core.signals.got_request_exception
  119. core.signals.request_finished
  120. core.signals.request_started
  121. core.validators.DecimalValidator
  122. core.validators.EmailValidator
  123. core.validators.EmailValidator.allowlist
  124. core.validators.EmailValidator.code
  125. core.validators.EmailValidator.message
  126. core.validators.FileExtensionValidator
  127. core.validators.MaxLengthValidator
  128. core.validators.MaxValueValidator
  129. core.validators.MinLengthValidator
  130. core.validators.MinValueValidator
  131. core.validators.ProhibitNullCharactersValidator
  132. core.validators.ProhibitNullCharactersValidator.code
  133. core.validators.ProhibitNullCharactersValidator.message
  134. core.validators.RegexValidator
  135. core.validators.RegexValidator.code
  136. core.validators.RegexValidator.flags
  137. core.validators.RegexValidator.inverse_match
  138. core.validators.RegexValidator.message
  139. core.validators.RegexValidator.regex
  140. core.validators.StepValueValidator
  141. core.validators.URLValidator
  142. core.validators.URLValidator.schemes
  143. core.validators.int_list_validator()
  144. core.validators.validate_comma_separated_integer_list
  145. core.validators.validate_email
  146. core.validators.validate_image_file_extension
  147. core.validators.validate_ipv46_address
  148. core.validators.validate_ipv4_address
  149. core.validators.validate_ipv6_address
  150. core.validators.validate_slug
  151. core.validators.validate_unicode_slug
  152. core.cache.cache
  153. core.cache.caches
  154. core.cache.utils.make_template_fragment_key()
  155. core.caches.cache.add()
  156. core.caches.cache.clear()
  157. core.caches.cache.close()
  158. core.caches.cache.decr()
  159. core.caches.cache.delete()
  160. core.caches.cache.delete_many()
  161. core.caches.cache.get()
  162. core.caches.cache.get_many()
  163. core.caches.cache.get_or_set()
  164. core.caches.cache.incr()
  165. core.caches.cache.set()
  166. core.caches.cache.set_many()
  167. core.caches.cache.touch()
  168. core.checks.register()
  169. core.mail.EmailMessage
  170. core.mail.backends.smtp.EmailBackend
  171. core.mail.get_connection()
  172. core.mail.mail_admins()
  173. core.mail.mail_managers()
  174. core.mail.send_mail()
  175. core.mail.send_mass_mail()
  176. core.serializers.get_serializer()
  177. core.serializers.json.DjangoJSONEncoder
  178. core.signing.Signer
  179. core.signing.TimestampSigner
  180. core.signing.TimestampSigner.sign()
  181. core.signing.TimestampSigner.sign_object()
  182. core.signing.TimestampSigner.unsign()
  183. core.signing.TimestampSigner.unsign_object()
  184. core.signing.dumps()
  185. core.signing.loads()
  186. core.mail.django.core.mail.outbox

backends

  1. db.backends.base.schema.BaseDatabaseSchemaEditor
  2. db.backends.base.schema.BaseDatabaseSchemaEditor.add_constraint()
  3. db.backends.base.schema.BaseDatabaseSchemaEditor.add_field()
  4. db.backends.base.schema.BaseDatabaseSchemaEditor.add_index()
  5. db.backends.base.schema.BaseDatabaseSchemaEditor.alter_db_table()
  6. db.backends.base.schema.BaseDatabaseSchemaEditor.alter_db_tablespace()
  7. db.backends.base.schema.BaseDatabaseSchemaEditor.alter_field()
  8. db.backends.base.schema.BaseDatabaseSchemaEditor.alter_index_together()
  9. db.backends.base.schema.BaseDatabaseSchemaEditor.alter_unique_together()
  10. db.backends.base.schema.BaseDatabaseSchemaEditor.create_model()
  11. db.backends.base.schema.BaseDatabaseSchemaEditor.delete_model()
  12. db.backends.base.schema.BaseDatabaseSchemaEditor.execute()
  13. db.backends.base.schema.BaseDatabaseSchemaEditor.remove_constraint()
  14. db.backends.base.schema.BaseDatabaseSchemaEditor.remove_field()
  15. db.backends.base.schema.BaseDatabaseSchemaEditor.remove_index()
  16. db.backends.base.schema.BaseDatabaseSchemaEditor.rename_index()
  17. db.backends.base.schema.SchemaEditor.connection
  18. db.backends.signals.connection_created
  19. db.backends.base.DatabaseWrapper.execute_wrapper()

migrations

  1. db.migrations.operations.AddConstraint
  2. db.migrations.operations.AddField
  3. db.migrations.operations.AddIndex
  4. db.migrations.operations.AlterField
  5. db.migrations.operations.AlterIndexTogether
  6. db.migrations.operations.AlterModelManagers
  7. db.migrations.operations.AlterModelOptions
  8. db.migrations.operations.AlterModelTable
  9. db.migrations.operations.AlterOrderWithRespectTo
  10. db.migrations.operations.AlterUniqueTogether
  11. db.migrations.operations.CreateModel
  12. db.migrations.operations.DeleteModel
  13. db.migrations.operations.RemoveConstraint
  14. db.migrations.operations.RemoveField
  15. db.migrations.operations.RemoveIndex
  16. db.migrations.operations.RenameField
  17. db.migrations.operations.RenameIndex
  18. db.migrations.operations.RenameModel
  19. db.migrations.operations.RunPython
  20. db.migrations.operations.RunPython.noop()
  21. db.migrations.operations.RunSQL
  22. db.migrations.operations.RunSQL.noop
  23. db.migrations.operations.SeparateDatabaseAndState
  24. db.migrations.Migration.initial

models

  1. db.models.Model.objects
  2. db.models.expressions.Case
  3. db.models.expressions.When
  4. db.models.BaseConstraint
  5. db.models.BaseConstraint.name
  6. db.models.BaseConstraint.validate()
  7. db.models.BaseConstraint.violation_error_message
  8. db.models.CheckConstraint
  9. db.models.CheckConstraint.check
  10. db.models.UniqueConstraint
  11. db.models.UniqueConstraint.condition
  12. db.models.UniqueConstraint.deferrable
  13. db.models.UniqueConstraint.expressions
  14. db.models.UniqueConstraint.fields
  15. db.models.UniqueConstraint.include
  16. db.models.UniqueConstraint.opclasses
  17. db.models.UniqueConstraint.violation_error_message
  18. db.models.functions.ACos
  19. db.models.functions.ASin
  20. db.models.functions.ATan
  21. db.models.functions.ATan2
  22. db.models.functions.Abs
  23. db.models.functions.Cast
  24. db.models.functions.Ceil
  25. db.models.functions.Chr
  26. db.models.functions.Coalesce
  27. db.models.functions.Collate
  28. db.models.functions.Concat
  29. db.models.functions.Cos
  30. db.models.functions.Cot
  31. db.models.functions.CumeDist
  32. db.models.functions.Degrees
  33. db.models.functions.DenseRank
  34. db.models.functions.Exp
  35. db.models.functions.Extract
  36. db.models.functions.ExtractDay
  37. db.models.functions.ExtractHour
  38. db.models.functions.ExtractIsoWeekDay
  39. db.models.functions.ExtractIsoYear
  40. db.models.functions.ExtractMinute
  41. db.models.functions.ExtractMonth
  42. db.models.functions.ExtractQuarter
  43. db.models.functions.ExtractSecond
  44. db.models.functions.ExtractWeek
  45. db.models.functions.ExtractWeekDay
  46. db.models.functions.ExtractYear
  47. db.models.functions.FirstValue
  48. db.models.functions.Floor
  49. db.models.functions.Greatest
  50. db.models.functions.JSONObject
  51. db.models.functions.LPad
  52. db.models.functions.LTrim
  53. db.models.functions.Lag
  54. db.models.functions.LastValue
  55. db.models.functions.Lead
  56. db.models.functions.Least
  57. db.models.functions.Left
  58. db.models.functions.Length
  59. db.models.functions.Ln
  60. db.models.functions.Log
  61. db.models.functions.Lower
  62. db.models.functions.MD5
  63. db.models.functions.Mod
  64. db.models.functions.Now
  65. db.models.functions.NthValue
  66. db.models.functions.Ntile
  67. db.models.functions.NullIf
  68. db.models.functions.Ord
  69. db.models.functions.PercentRank
  70. db.models.functions.Pi
  71. db.models.functions.Power
  72. db.models.functions.RPad
  73. db.models.functions.RTrim
  74. db.models.functions.Radians
  75. db.models.functions.Random
  76. db.models.functions.Rank
  77. db.models.functions.Repeat
  78. db.models.functions.Replace
  79. db.models.functions.Reverse
  80. db.models.functions.Right
  81. db.models.functions.Round
  82. db.models.functions.RowNumber
  83. db.models.functions.SHA1
  84. db.models.functions.SHA224
  85. db.models.functions.SHA256
  86. db.models.functions.SHA384
  87. db.models.functions.SHA512
  88. db.models.functions.Sign
  89. db.models.functions.Sin
  90. db.models.functions.Sqrt
  91. db.models.functions.StrIndex
  92. db.models.functions.Substr
  93. db.models.functions.Tan
  94. db.models.functions.Trim
  95. db.models.functions.Trunc
  96. db.models.functions.TruncDate
  97. db.models.functions.TruncDay
  98. db.models.functions.TruncHour
  99. db.models.functions.TruncMinute
  100. db.models.functions.TruncMonth
  101. db.models.functions.TruncQuarter
  102. db.models.functions.TruncSecond
  103. db.models.functions.TruncTime
  104. db.models.functions.TruncWeek
  105. db.models.functions.TruncYear
  106. db.models.functions.Upper
  107. db.models.Aggregate
  108. db.models.Aggregate.allow_distinct
  109. db.models.Aggregate.empty_result_set_value
  110. db.models.Aggregate.function
  111. db.models.Aggregate.template
  112. db.models.Aggregate.window_compatible
  113. db.models.Exists
  114. db.models.Expression
  115. db.models.Expression.asc()
  116. db.models.Expression.contains_aggregate
  117. db.models.Expression.contains_over_clause
  118. db.models.Expression.convert_value()
  119. db.models.Expression.desc()
  120. db.models.Expression.empty_result_set_value
  121. db.models.Expression.filterable
  122. db.models.Expression.get_group_by_cols()
  123. db.models.Expression.get_source_expressions()
  124. db.models.Expression.relabeled_clone()
  125. db.models.Expression.resolve_expression()
  126. db.models.Expression.reverse_ordering()
  127. db.models.Expression.set_source_expressions()
  128. db.models.Expression.window_compatible
  129. db.models.ExpressionWrapper
  130. db.models.F
  131. db.models.Func
  132. db.models.Func.arg_joiner
  133. db.models.Func.arity
  134. db.models.Func.as_sql()
  135. db.models.Func.function
  136. db.models.Func.template
  137. db.models.OuterRef
  138. db.models.Subquery
  139. db.models.Value
  140. db.models.expressions.RawSQL
  141. db.models.expressions.RowRange
  142. db.models.expressions.RowRange.frame_type
  143. db.models.expressions.ValueRange
  144. db.models.expressions.ValueRange.frame_type
  145. db.models.expressions.Window
  146. db.models.expressions.Window.filterable
  147. db.models.expressions.Window.template
  148. db.models.AutoField
  149. db.models.BigAutoField
  150. db.models.BigIntegerField
  151. db.models.BinaryField
  152. db.models.BinaryField.max_length
  153. db.models.BooleanField
  154. db.models.CASCADE
  155. db.models.CharField
  156. db.models.CharField.db_collation
  157. db.models.CharField.max_length
  158. db.models.DO_NOTHING
  159. db.models.DateField
  160. db.models.DateField.auto_now
  161. db.models.DateField.auto_now_add
  162. db.models.DateTimeField
  163. db.models.DecimalField
  164. db.models.DecimalField.decimal_places
  165. db.models.DecimalField.max_digits
  166. db.models.DurationField
  167. db.models.EmailField
  168. db.models.Field
  169. db.models.Field.auto_created
  170. db.models.Field.blank
  171. db.models.Field.choices
  172. db.models.Field.concrete
  173. db.models.Field.db_column
  174. db.models.Field.db_index
  175. db.models.Field.db_tablespace
  176. db.models.Field.db_type()
  177. db.models.Field.deconstruct()
  178. db.models.Field.default
  179. db.models.Field.description
  180. db.models.Field.descriptor_class
  181. db.models.Field.editable
  182. db.models.Field.error_messages
  183. db.models.Field.formfield()
  184. db.models.Field.from_db_value()
  185. db.models.Field.get_db_prep_save()
  186. db.models.Field.get_db_prep_value()
  187. db.models.Field.get_internal_type()
  188. db.models.Field.get_prep_value()
  189. db.models.Field.help_text
  190. db.models.Field.hidden
  191. db.models.Field.is_relation
  192. db.models.Field.many_to_many
  193. db.models.Field.many_to_one
  194. db.models.Field.model
  195. db.models.Field.null
  196. db.models.Field.one_to_many
  197. db.models.Field.one_to_one
  198. db.models.Field.pre_save()
  199. db.models.Field.primary_key
  200. db.models.Field.rel_db_type()
  201. db.models.Field.related_model
  202. db.models.Field.to_python()
  203. db.models.Field.unique
  204. db.models.Field.unique_for_date
  205. db.models.Field.unique_for_month
  206. db.models.Field.unique_for_year
  207. db.models.Field.validators
  208. db.models.Field.value_from_object()
  209. db.models.Field.value_to_string()
  210. db.models.Field.verbose_name
  211. db.models.FileField
  212. db.models.FileField.storage
  213. db.models.FileField.upload_to
  214. db.models.FilePathField
  215. db.models.FilePathField.allow_files
  216. db.models.FilePathField.allow_folders
  217. db.models.FilePathField.match
  218. db.models.FilePathField.path
  219. db.models.FilePathField.recursive
  220. db.models.FloatField
  221. db.models.ForeignKey
  222. db.models.ForeignKey.db_constraint
  223. db.models.ForeignKey.limit_choices_to
  224. db.models.ForeignKey.on_delete
  225. db.models.ForeignKey.related_name
  226. db.models.ForeignKey.related_query_name
  227. db.models.ForeignKey.swappable
  228. db.models.ForeignKey.to_field
  229. db.models.GenericIPAddressField
  230. db.models.GenericIPAddressField.protocol
  231. db.models.GenericIPAddressField.unpack_ipv4
  232. db.models.ImageField
  233. db.models.ImageField.height_field
  234. db.models.ImageField.width_field
  235. db.models.IntegerField
  236. db.models.JSONField
  237. db.models.JSONField.decoder
  238. db.models.JSONField.encoder
  239. db.models.ManyToManyField
  240. db.models.ManyToManyField.db_constraint
  241. db.models.ManyToManyField.db_table
  242. db.models.ManyToManyField.limit_choices_to
  243. db.models.ManyToManyField.related_name
  244. db.models.ManyToManyField.related_query_name
  245. db.models.ManyToManyField.swappable
  246. db.models.ManyToManyField.symmetrical
  247. db.models.ManyToManyField.through
  248. db.models.ManyToManyField.through_fields
  249. db.models.OneToOneField
  250. db.models.OneToOneField.parent_link
  251. db.models.PROTECT
  252. db.models.PositiveBigIntegerField
  253. db.models.PositiveIntegerField
  254. db.models.PositiveSmallIntegerField
  255. db.models.RESTRICT
  256. db.models.SET()
  257. db.models.SET_DEFAULT
  258. db.models.SET_NULL
  259. db.models.SlugField
  260. db.models.SlugField.allow_unicode
  261. db.models.SmallAutoField
  262. db.models.SmallIntegerField
  263. db.models.TextField
  264. db.models.TextField.db_collation
  265. db.models.TimeField
  266. db.models.URLField
  267. db.models.UUIDField
  268. db.models.fields.files.FieldFile
  269. db.models.fields.files.FieldFile.close()
  270. db.models.fields.files.FieldFile.delete()
  271. db.models.fields.files.FieldFile.name
  272. db.models.fields.files.FieldFile.open()
  273. db.models.fields.files.FieldFile.path
  274. db.models.fields.files.FieldFile.save()
  275. db.models.fields.files.FieldFile.size
  276. db.models.fields.files.FieldFile.url
  277. db.models.Index
  278. db.models.Index.condition
  279. db.models.Index.db_tablespace
  280. db.models.Index.expressions
  281. db.models.Index.fields
  282. db.models.Index.include
  283. db.models.Index.name
  284. db.models.Index.opclasses
  285. db.models.Model
  286. db.models.Model.__eq__()
  287. db.models.Model.__hash__()
  288. db.models.Model.__str__()
  289. db.models.Model._state
  290. db.models.Model.clean()
  291. db.models.Model.clean_fields()
  292. db.models.Model.delete()
  293. db.models.Model.from_db()
  294. db.models.Model.full_clean()
  295. db.models.Model.get_FOO_display()
  296. db.models.Model.get_absolute_url()
  297. db.models.Model.get_deferred_fields()
  298. db.models.Model.get_next_by_FOO()
  299. db.models.Model.get_previous_by_FOO()
  300. db.models.Model.pk
  301. db.models.Model.refresh_from_db()
  302. db.models.Model.save()
  303. db.models.Model.validate_constraints()
  304. db.models.Model.validate_unique()
  305. db.models.Lookup
  306. db.models.Lookup.lhs
  307. db.models.Lookup.lookup_name
  308. db.models.Lookup.process_lhs()
  309. db.models.Lookup.process_rhs()
  310. db.models.Lookup.rhs
  311. db.models.Transform
  312. db.models.Transform.bilateral
  313. db.models.Transform.lhs
  314. db.models.Transform.lookup_name
  315. db.models.Transform.output_field
  316. db.models.as_sql()
  317. db.models.as_vendorname()
  318. db.models.get_lookup()
  319. db.models.get_transform()
  320. db.models.lookups.RegisterLookupMixin
  321. db.models.lookups.RegisterLookupMixin.get_lookup()
  322. db.models.lookups.RegisterLookupMixin.get_lookups()
  323. db.models.lookups.RegisterLookupMixin.get_transform()
  324. db.models.lookups.RegisterLookupMixin.register_lookup()
  325. db.models.output_field
  326. db.models.options.Options
  327. db.models.options.Options.get_field()
  328. db.models.options.Options.get_fields()
  329. db.models.Options.abstract
  330. db.models.Options.app_label
  331. db.models.Options.base_manager_name
  332. db.models.Options.constraints
  333. db.models.Options.db_table
  334. db.models.Options.db_tablespace
  335. db.models.Options.default_manager_name
  336. db.models.Options.default_permissions
  337. db.models.Options.default_related_name
  338. db.models.Options.get_latest_by
  339. db.models.Options.index_together
  340. db.models.Options.indexes
  341. db.models.Options.label
  342. db.models.Options.label_lower
  343. db.models.Options.managed
  344. db.models.Options.order_with_respect_to
  345. db.models.Options.ordering
  346. db.models.Options.permissions
  347. db.models.Options.proxy
  348. db.models.Options.required_db_features
  349. db.models.Options.required_db_vendor
  350. db.models.Options.select_on_save
  351. db.models.Options.unique_together
  352. db.models.Options.verbose_name
  353. db.models.Options.verbose_name_plural
  354. db.models.Avg
  355. db.models.Avg.distinct
  356. db.models.Count
  357. db.models.Count.distinct
  358. db.models.FilteredRelation
  359. db.models.FilteredRelation.condition
  360. db.models.FilteredRelation.relation_name
  361. db.models.Max
  362. db.models.Min
  363. db.models.Prefetch
  364. db.models.Q
  365. db.models.StdDev
  366. db.models.StdDev.sample
  367. db.models.Sum
  368. db.models.Sum.distinct
  369. db.models.Variance
  370. db.models.Variance.sample
  371. db.models.prefetch_related_objects()
  372. db.models.query.QuerySet
  373. db.models.query.QuerySet.aaggregate()
  374. db.models.query.QuerySet.abulk_create()
  375. db.models.query.QuerySet.abulk_update()
  376. db.models.query.QuerySet.acontains()
  377. db.models.query.QuerySet.acount()
  378. db.models.query.QuerySet.acreate()
  379. db.models.query.QuerySet.adelete()
  380. db.models.query.QuerySet.aearliest()
  381. db.models.query.QuerySet.aexists()
  382. db.models.query.QuerySet.aexplain()
  383. db.models.query.QuerySet.afirst()
  384. db.models.query.QuerySet.aget()
  385. db.models.query.QuerySet.aget_or_create()
  386. db.models.query.QuerySet.aggregate()
  387. db.models.query.QuerySet.ain_bulk()
  388. db.models.query.QuerySet.aiterator()
  389. db.models.query.QuerySet.alast()
  390. db.models.query.QuerySet.alatest()
  391. db.models.query.QuerySet.alias()
  392. db.models.query.QuerySet.all()
  393. db.models.query.QuerySet.annotate()
  394. db.models.query.QuerySet.as_manager()
  395. db.models.query.QuerySet.aupdate()
  396. db.models.query.QuerySet.aupdate_or_create()
  397. db.models.query.QuerySet.bulk_create()
  398. db.models.query.QuerySet.bulk_update()
  399. db.models.query.QuerySet.contains()
  400. db.models.query.QuerySet.count()
  401. db.models.query.QuerySet.create()
  402. db.models.query.QuerySet.dates()
  403. db.models.query.QuerySet.datetimes()
  404. db.models.query.QuerySet.db
  405. db.models.query.QuerySet.defer()
  406. db.models.query.QuerySet.delete()
  407. db.models.query.QuerySet.difference()
  408. db.models.query.QuerySet.distinct()
  409. db.models.query.QuerySet.earliest()
  410. db.models.query.QuerySet.exclude()
  411. db.models.query.QuerySet.exists()
  412. db.models.query.QuerySet.explain()
  413. db.models.query.QuerySet.extra()
  414. db.models.query.QuerySet.filter()
  415. db.models.query.QuerySet.first()
  416. db.models.query.QuerySet.get()
  417. db.models.query.QuerySet.get_or_create()
  418. db.models.query.QuerySet.in_bulk()
  419. db.models.query.QuerySet.intersection()
  420. db.models.query.QuerySet.iterator()
  421. db.models.query.QuerySet.last()
  422. db.models.query.QuerySet.latest()
  423. db.models.query.QuerySet.none()
  424. db.models.query.QuerySet.only()
  425. db.models.query.QuerySet.order_by()
  426. db.models.query.QuerySet.ordered
  427. db.models.query.QuerySet.prefetch_related()
  428. db.models.query.QuerySet.raw()
  429. db.models.query.QuerySet.reverse()
  430. db.models.query.QuerySet.select_for_update()
  431. db.models.query.QuerySet.select_related()
  432. db.models.query.QuerySet.union()
  433. db.models.query.QuerySet.update()
  434. db.models.query.QuerySet.update_or_create()
  435. db.models.query.QuerySet.using()
  436. db.models.query.QuerySet.values()
  437. db.models.query.QuerySet.values_list()
  438. db.models.fields.related.RelatedManager
  439. db.models.fields.related.RelatedManager.add()
  440. db.models.fields.related.RelatedManager.clear()
  441. db.models.fields.related.RelatedManager.create()
  442. db.models.fields.related.RelatedManager.remove()
  443. db.models.fields.related.RelatedManager.set()
  444. db.models.signals.class_prepared
  445. db.models.signals.m2m_changed
  446. db.models.signals.post_delete
  447. db.models.signals.post_init
  448. db.models.signals.post_migrate
  449. db.models.signals.post_save
  450. db.models.signals.pre_delete
  451. db.models.signals.pre_init
  452. db.models.signals.pre_migrate
  453. db.models.signals.pre_save
  454. db.models.Manager
  455. db.models.Model._base_manager
  456. db.models.Model._default_manager
  457. db.models.from_queryset()
  458. db.models.CursorWrapper.callproc()
  459. db.models.Manager.raw()

transaction

  1. db.transaction.atomic()
  2. db.transaction.clean_savepoints()
  3. db.transaction.commit()
  4. db.transaction.get_autocommit()
  5. db.transaction.get_rollback()
  6. db.transaction.non_atomic_requests()
  7. db.transaction.on_commit()
  8. db.transaction.rollback()
  9. db.transaction.savepoint()
  10. db.transaction.savepoint_commit()
  11. db.transaction.savepoint_rollback()
  12. db.transaction.set_autocommit()
  13. db.transaction.set_rollback()

dispatch

  1. dispatch.Signal
  2. dispatch.Signal.connect()
  3. dispatch.Signal.disconnect()
  4. dispatch.Signal.send()
  5. dispatch.Signal.send_robust()
  6. dispatch.receiver()

flatpages

  1. flatpages.middleware.FlatpageFallbackMiddleware
  2. flatpages.models.FlatPage
  3. flatpages.sitemaps.FlatPageSitemap

forms

  1. forms.BoundField
  2. forms.BoundField.as_hidden()
  3. forms.BoundField.as_widget()
  4. forms.BoundField.auto_id
  5. forms.BoundField.css_classes()
  6. forms.BoundField.data
  7. forms.BoundField.errors
  8. forms.BoundField.field
  9. forms.BoundField.form
  10. forms.BoundField.help_text
  11. forms.BoundField.html_name
  12. forms.BoundField.id_for_label
  13. forms.BoundField.initial
  14. forms.BoundField.is_hidden
  15. forms.BoundField.label
  16. forms.BoundField.label_tag()
  17. forms.BoundField.legend_tag()
  18. forms.BoundField.name
  19. forms.BoundField.use_fieldset
  20. forms.BoundField.value()
  21. forms.BoundField.widget_type
  22. forms.ErrorList
  23. forms.ErrorList.as_text()
  24. forms.ErrorList.as_ul()
  25. forms.ErrorList.error_class
  26. forms.ErrorList.get_context()
  27. forms.ErrorList.render()
  28. forms.ErrorList.renderer
  29. forms.ErrorList.template_name
  30. forms.ErrorList.template_name_text
  31. forms.ErrorList.template_name_ul
  32. forms.Field.get_bound_field()
  33. forms.Form
  34. forms.Form.add_error()
  35. forms.Form.as_div()
  36. forms.Form.as_p()
  37. forms.Form.as_table()
  38. forms.Form.as_ul()
  39. forms.Form.auto_id
  40. forms.Form.changed_data
  41. forms.Form.clean()
  42. forms.Form.cleaned_data
  43. forms.Form.default_renderer
  44. forms.Form.error_css_class
  45. forms.Form.errors
  46. forms.Form.errors.as_data()
  47. forms.Form.errors.as_json()
  48. forms.Form.errors.get_json_data()
  49. forms.Form.field_order
  50. forms.Form.fields
  51. forms.Form.get_context()
  52. forms.Form.get_initial_for_field()
  53. forms.Form.has_changed()
  54. forms.Form.has_error()
  55. forms.Form.initial
  56. forms.Form.is_bound
  57. forms.Form.is_multipart()
  58. forms.Form.is_valid()
  59. forms.Form.label_suffix
  60. forms.Form.non_field_errors()
  61. forms.Form.order_fields()
  62. forms.Form.prefix
  63. forms.Form.render()
  64. forms.Form.required_css_class
  65. forms.Form.template_name
  66. forms.Form.template_name_div
  67. forms.Form.template_name_label
  68. forms.Form.template_name_p
  69. forms.Form.template_name_table
  70. forms.Form.template_name_ul
  71. forms.Form.use_required_attribute
  72. forms.BooleanField
  73. forms.CharField
  74. forms.CharField.empty_value
  75. forms.CharField.max_length
  76. forms.CharField.min_length
  77. forms.CharField.strip
  78. forms.ChoiceField
  79. forms.ChoiceField.choices
  80. forms.ComboField
  81. forms.ComboField.fields
  82. forms.DateField
  83. forms.DateField.input_formats
  84. forms.DateTimeField
  85. forms.DateTimeField.input_formats
  86. forms.DecimalField
  87. forms.DecimalField.decimal_places
  88. forms.DecimalField.max_digits
  89. forms.DecimalField.max_value
  90. forms.DecimalField.min_value
  91. forms.DecimalField.step_size
  92. forms.DurationField
  93. forms.EmailField
  94. forms.Field
  95. forms.Field.clean()
  96. forms.Field.disabled
  97. forms.Field.error_messages
  98. forms.Field.has_changed()
  99. forms.Field.help_text
  100. forms.Field.initial
  101. forms.Field.label
  102. forms.Field.label_suffix
  103. forms.Field.localize
  104. forms.Field.required
  105. forms.Field.validators
  106. forms.Field.widget
  107. forms.FileField
  108. forms.FilePathField
  109. forms.FilePathField.allow_files
  110. forms.FilePathField.allow_folders
  111. forms.FilePathField.match
  112. forms.FilePathField.path
  113. forms.FilePathField.recursive
  114. forms.FloatField
  115. forms.FloatField.max_value
  116. forms.FloatField.min_value
  117. forms.FloatField.step_size
  118. forms.GenericIPAddressField
  119. forms.GenericIPAddressField.protocol
  120. forms.GenericIPAddressField.unpack_ipv4
  121. forms.ImageField
  122. forms.IntegerField
  123. forms.IntegerField.max_value
  124. forms.IntegerField.min_value
  125. forms.IntegerField.step_size
  126. forms.JSONField
  127. forms.JSONField.decoder
  128. forms.JSONField.encoder
  129. forms.ModelChoiceField
  130. forms.ModelChoiceField.blank
  131. forms.ModelChoiceField.empty_label
  132. forms.ModelChoiceField.iterator
  133. forms.ModelChoiceField.queryset
  134. forms.ModelChoiceField.to_field_name
  135. forms.ModelChoiceIterator
  136. forms.ModelChoiceIterator.__iter__()
  137. forms.ModelChoiceIterator.field
  138. forms.ModelChoiceIteratorValue
  139. forms.ModelChoiceIteratorValue.__str__()
  140. forms.ModelChoiceIteratorValue.instance
  141. forms.ModelChoiceIteratorValue.value
  142. forms.ModelMultipleChoiceField
  143. forms.ModelMultipleChoiceField.iterator
  144. forms.ModelMultipleChoiceField.queryset
  145. forms.ModelMultipleChoiceField.to_field_name
  146. forms.MultiValueField
  147. forms.MultiValueField.compress()
  148. forms.MultiValueField.fields
  149. forms.MultiValueField.require_all_fields
  150. forms.MultiValueField.widget
  151. forms.MultipleChoiceField
  152. forms.NullBooleanField
  153. forms.RegexField
  154. forms.RegexField.regex
  155. forms.RegexField.strip
  156. forms.SlugField
  157. forms.SlugField.allow_unicode
  158. forms.SlugField.empty_value
  159. forms.SplitDateTimeField
  160. forms.SplitDateTimeField.input_date_formats
  161. forms.SplitDateTimeField.input_time_formats
  162. forms.TimeField
  163. forms.TimeField.input_formats
  164. forms.TypedChoiceField
  165. forms.TypedChoiceField.coerce
  166. forms.TypedChoiceField.empty_value
  167. forms.TypedMultipleChoiceField
  168. forms.URLField
  169. forms.UUIDField
  170. forms.formsets.formset_factory()
  171. forms.models.inlineformset_factory()
  172. forms.models.modelform_factory()
  173. forms.models.modelformset_factory()
  174. forms.renderers.BaseRenderer
  175. forms.renderers.BaseRenderer.form_template_name
  176. forms.renderers.BaseRenderer.formset_template_name
  177. forms.renderers.BaseRenderer.get_template()
  178. forms.renderers.BaseRenderer.render()
  179. forms.renderers.DjangoDivFormRenderer
  180. forms.renderers.DjangoTemplates
  181. forms.renderers.Jinja2
  182. forms.renderers.Jinja2DivFormRenderer
  183. forms.renderers.TemplatesSetting
  184. forms.CheckboxInput
  185. forms.CheckboxInput.check_test
  186. forms.CheckboxSelectMultiple
  187. forms.ClearableFileInput
  188. forms.DateInput
  189. forms.DateInput.format
  190. forms.DateTimeInput
  191. forms.DateTimeInput.format
  192. forms.EmailInput
  193. forms.FileInput
  194. forms.HiddenInput
  195. forms.MultiWidget
  196. forms.MultiWidget.decompress()
  197. forms.MultiWidget.get_context()
  198. forms.MultiWidget.widgets
  199. forms.MultipleHiddenInput
  200. forms.NullBooleanSelect
  201. forms.NumberInput
  202. forms.PasswordInput
  203. forms.PasswordInput.render_value
  204. forms.RadioSelect
  205. forms.Select
  206. forms.Select.choices
  207. forms.SelectDateWidget
  208. forms.SelectDateWidget.empty_label
  209. forms.SelectDateWidget.months
  210. forms.SelectDateWidget.years
  211. forms.SelectMultiple
  212. forms.SplitDateTimeWidget
  213. forms.SplitDateTimeWidget.date_attrs
  214. forms.SplitDateTimeWidget.date_format
  215. forms.SplitDateTimeWidget.time_attrs
  216. forms.SplitDateTimeWidget.time_format
  217. forms.SplitHiddenDateTimeWidget
  218. forms.TextInput
  219. forms.Textarea
  220. forms.TimeInput
  221. forms.TimeInput.format
  222. forms.URLInput
  223. forms.Widget
  224. forms.Widget.attrs
  225. forms.Widget.format_value()
  226. forms.Widget.get_context()
  227. forms.Widget.id_for_label()
  228. forms.Widget.render()
  229. forms.Widget.supports_microseconds
  230. forms.Widget.use_fieldset
  231. forms.Widget.use_required_attribute()
  232. forms.Widget.value_from_datadict()
  233. forms.Widget.value_omitted_from_data()
  234. forms.formsets.BaseFormSet
  235. forms.formsets.BaseFormSet.as_p()
  236. forms.formsets.BaseFormSet.as_table()
  237. forms.formsets.BaseFormSet.as_ul()
  238. forms.formsets.BaseFormSet.can_delete
  239. forms.formsets.BaseFormSet.can_delete_extra
  240. forms.formsets.BaseFormSet.can_order
  241. forms.formsets.BaseFormSet.deletion_widget
  242. forms.formsets.BaseFormSet.get_context()
  243. forms.formsets.BaseFormSet.get_deletion_widget()
  244. forms.formsets.BaseFormSet.get_ordering_widget()
  245. forms.formsets.BaseFormSet.ordering_widget
  246. forms.formsets.BaseFormSet.render()
  247. forms.formsets.BaseFormSet.renderer
  248. forms.formsets.BaseFormSet.template_name
  249. forms.formsets.BaseFormSet.template_name_div
  250. forms.formsets.BaseFormSet.template_name_p
  251. forms.formsets.BaseFormSet.template_name_table
  252. forms.formsets.BaseFormSet.template_name_ul
  253. forms.formsets.BaseFormSet.total_error_count()
  254. forms.ModelForm
  255. forms.models.BaseInlineFormSet
  256. forms.models.BaseModelFormSet
  257. forms.models.BaseModelFormSet.changed_objects
  258. forms.models.BaseModelFormSet.deleted_objects
  259. forms.models.BaseModelFormSet.new_objects

gis

  1. gis.admin.GISModelAdmin
  2. gis.admin.GISModelAdmin.gis_widget
  3. gis.admin.GISModelAdmin.gis_widget_kwargs
  4. gis.admin.GeoModelAdmin
  5. gis.admin.GeoModelAdmin.default_lat
  6. gis.admin.GeoModelAdmin.default_lon
  7. gis.admin.GeoModelAdmin.default_zoom
  8. gis.admin.GeoModelAdmin.extra_js
  9. gis.admin.GeoModelAdmin.map_height
  10. gis.admin.GeoModelAdmin.map_template
  11. gis.admin.GeoModelAdmin.map_width
  12. gis.admin.GeoModelAdmin.modifiable
  13. gis.admin.GeoModelAdmin.openlayers_url
  14. gis.admin.OSMGeoAdmin
  15. gis.feeds.Feed
  16. gis.feeds.Feed.geometry()
  17. gis.feeds.Feed.item_geometry()
  18. gis.feeds.GeoAtom1Feed
  19. gis.feeds.GeoRSSFeed
  20. gis.feeds.W3CGeoFeed
  21. gis.forms.Field.geom_type
  22. gis.forms.Field.srid
  23. gis.forms.GeometryCollectionField
  24. gis.forms.GeometryField
  25. gis.forms.LineStringField
  26. gis.forms.MultiLineStringField
  27. gis.forms.MultiPointField
  28. gis.forms.MultiPolygonField
  29. gis.forms.PointField
  30. gis.forms.PolygonField
  31. gis.forms.widgets.BaseGeometryWidget
  32. gis.forms.widgets.BaseGeometryWidget.display_raw
  33. gis.forms.widgets.BaseGeometryWidget.geom_type
  34. gis.forms.widgets.BaseGeometryWidget.map_height
  35. gis.forms.widgets.BaseGeometryWidget.map_srid
  36. gis.forms.widgets.BaseGeometryWidget.map_width
  37. gis.forms.widgets.BaseGeometryWidget.supports_3d
  38. gis.forms.widgets.BaseGeometryWidget.template_name
  39. gis.forms.widgets.OSMWidget
  40. gis.forms.widgets.OSMWidget.default_lat
  41. gis.forms.widgets.OSMWidget.default_lon
  42. gis.forms.widgets.OSMWidget.default_zoom
  43. gis.forms.widgets.OSMWidget.template_name
  44. gis.forms.widgets.OpenLayersWidget
  45. gis.db.models.functions.Area
  46. gis.db.models.functions.AsGML
  47. gis.db.models.functions.AsGeoJSON
  48. gis.db.models.functions.AsKML
  49. gis.db.models.functions.AsSVG
  50. gis.db.models.functions.AsWKB
  51. gis.db.models.functions.AsWKT
  52. gis.db.models.functions.Azimuth
  53. gis.db.models.functions.BoundingCircle
  54. gis.db.models.functions.Centroid
  55. gis.db.models.functions.Difference
  56. gis.db.models.functions.Distance
  57. gis.db.models.functions.Envelope
  58. gis.db.models.functions.ForcePolygonCW
  59. gis.db.models.functions.GeoHash
  60. gis.db.models.functions.GeometryDistance
  61. gis.db.models.functions.Intersection
  62. gis.db.models.functions.IsValid
  63. gis.db.models.functions.Length
  64. gis.db.models.functions.LineLocatePoint
  65. gis.db.models.functions.MakeValid
  66. gis.db.models.functions.MemSize
  67. gis.db.models.functions.NumGeometries
  68. gis.db.models.functions.NumPoints
  69. gis.db.models.functions.Perimeter
  70. gis.db.models.functions.PointOnSurface
  71. gis.db.models.functions.Reverse
  72. gis.db.models.functions.Scale
  73. gis.db.models.functions.SnapToGrid
  74. gis.db.models.functions.SymDifference
  75. gis.db.models.functions.Transform
  76. gis.db.models.functions.Translate
  77. gis.db.models.functions.Union
  78. gis.gdal.CoordTransform
  79. gis.gdal.DataSource
  80. gis.gdal.DataSource.layer_count
  81. gis.gdal.DataSource.name
  82. gis.gdal.Driver
  83. gis.gdal.Driver.driver_count
  84. gis.gdal.Envelope
  85. gis.gdal.Envelope.expand_to_include()
  86. gis.gdal.Envelope.ll
  87. gis.gdal.Envelope.max_x
  88. gis.gdal.Envelope.max_y
  89. gis.gdal.Envelope.min_x
  90. gis.gdal.Envelope.min_y
  91. gis.gdal.Envelope.tuple
  92. gis.gdal.Envelope.ur
  93. gis.gdal.Envelope.wkt
  94. gis.gdal.Feature
  95. gis.gdal.Feature.fid
  96. gis.gdal.Feature.fields
  97. gis.gdal.Feature.geom
  98. gis.gdal.Feature.geom_type
  99. gis.gdal.Feature.get
  100. gis.gdal.Feature.index
  101. gis.gdal.Feature.layer_name
  102. gis.gdal.Feature.num_fields
  103. gis.gdal.Field
  104. gis.gdal.Field.as_datetime()
  105. gis.gdal.Field.as_double()
  106. gis.gdal.Field.as_int()
  107. gis.gdal.Field.as_string()
  108. gis.gdal.Field.name
  109. gis.gdal.Field.precision
  110. gis.gdal.Field.type
  111. gis.gdal.Field.type_name
  112. gis.gdal.Field.value
  113. gis.gdal.Field.width
  114. gis.gdal.GDALBand
  115. gis.gdal.GDALBand.color_interp()
  116. gis.gdal.GDALBand.data()
  117. gis.gdal.GDALBand.datatype()
  118. gis.gdal.GDALBand.description
  119. gis.gdal.GDALBand.height
  120. gis.gdal.GDALBand.max
  121. gis.gdal.GDALBand.mean
  122. gis.gdal.GDALBand.metadata
  123. gis.gdal.GDALBand.min
  124. gis.gdal.GDALBand.nodata_value
  125. gis.gdal.GDALBand.pixel_count
  126. gis.gdal.GDALBand.statistics()
  127. gis.gdal.GDALBand.std
  128. gis.gdal.GDALBand.width
  129. gis.gdal.GDALRaster
  130. gis.gdal.GDALRaster.bands
  131. gis.gdal.GDALRaster.driver
  132. gis.gdal.GDALRaster.extent
  133. gis.gdal.GDALRaster.geotransform
  134. gis.gdal.GDALRaster.height
  135. gis.gdal.GDALRaster.info
  136. gis.gdal.GDALRaster.is_vsi_based
  137. gis.gdal.GDALRaster.metadata
  138. gis.gdal.GDALRaster.name
  139. gis.gdal.GDALRaster.origin
  140. gis.gdal.GDALRaster.scale
  141. gis.gdal.GDALRaster.skew
  142. gis.gdal.GDALRaster.srid
  143. gis.gdal.GDALRaster.srs
  144. gis.gdal.GDALRaster.transform()
  145. gis.gdal.GDALRaster.vsi_buffer
  146. gis.gdal.GDALRaster.warp()
  147. gis.gdal.GDALRaster.width
  148. gis.gdal.GeometryCollection
  149. gis.gdal.GeometryCollection.add()
  150. gis.gdal.Layer
  151. gis.gdal.Layer.extent
  152. gis.gdal.Layer.field_precisions
  153. gis.gdal.Layer.field_widths
  154. gis.gdal.Layer.fields
  155. gis.gdal.Layer.geom_type
  156. gis.gdal.Layer.get_fields()
  157. gis.gdal.Layer.get_geoms()
  158. gis.gdal.Layer.name
  159. gis.gdal.Layer.num_feat
  160. gis.gdal.Layer.num_fields
  161. gis.gdal.Layer.spatial_filter
  162. gis.gdal.Layer.srs
  163. gis.gdal.Layer.test_capability()
  164. gis.gdal.LineString
  165. gis.gdal.LineString.x
  166. gis.gdal.LineString.y
  167. gis.gdal.LineString.z
  168. gis.gdal.OGRGeomType
  169. gis.gdal.OGRGeomType.django
  170. gis.gdal.OGRGeomType.name
  171. gis.gdal.OGRGeomType.num
  172. gis.gdal.OGRGeometry
  173. gis.gdal.OGRGeometry.__getitem__()
  174. gis.gdal.OGRGeometry.__iter__()
  175. gis.gdal.OGRGeometry.__len__()
  176. gis.gdal.OGRGeometry.area
  177. gis.gdal.OGRGeometry.boundary()
  178. gis.gdal.OGRGeometry.clone()
  179. gis.gdal.OGRGeometry.close_rings()
  180. gis.gdal.OGRGeometry.contains()
  181. gis.gdal.OGRGeometry.convex_hull
  182. gis.gdal.OGRGeometry.coord_dim
  183. gis.gdal.OGRGeometry.coords
  184. gis.gdal.OGRGeometry.crosses()
  185. gis.gdal.OGRGeometry.difference()
  186. gis.gdal.OGRGeometry.dimension
  187. gis.gdal.OGRGeometry.disjoint()
  188. gis.gdal.OGRGeometry.envelope
  189. gis.gdal.OGRGeometry.equals()
  190. gis.gdal.OGRGeometry.ewkt
  191. gis.gdal.OGRGeometry.extent
  192. gis.gdal.OGRGeometry.from_bbox()
  193. gis.gdal.OGRGeometry.from_gml()
  194. gis.gdal.OGRGeometry.geom_count
  195. gis.gdal.OGRGeometry.geom_name
  196. gis.gdal.OGRGeometry.geom_type
  197. gis.gdal.OGRGeometry.geos
  198. gis.gdal.OGRGeometry.gml
  199. gis.gdal.OGRGeometry.hex
  200. gis.gdal.OGRGeometry.intersection()
  201. gis.gdal.OGRGeometry.intersects()
  202. gis.gdal.OGRGeometry.json
  203. gis.gdal.OGRGeometry.kml
  204. gis.gdal.OGRGeometry.num_coords
  205. gis.gdal.OGRGeometry.num_points
  206. gis.gdal.OGRGeometry.overlaps()
  207. gis.gdal.OGRGeometry.point_count
  208. gis.gdal.OGRGeometry.srid
  209. gis.gdal.OGRGeometry.srs
  210. gis.gdal.OGRGeometry.sym_difference()
  211. gis.gdal.OGRGeometry.touches()
  212. gis.gdal.OGRGeometry.transform()
  213. gis.gdal.OGRGeometry.tuple
  214. gis.gdal.OGRGeometry.union()
  215. gis.gdal.OGRGeometry.within()
  216. gis.gdal.OGRGeometry.wkb
  217. gis.gdal.OGRGeometry.wkb_size
  218. gis.gdal.OGRGeometry.wkt
  219. gis.gdal.Point
  220. gis.gdal.Point.x
  221. gis.gdal.Point.y
  222. gis.gdal.Point.z
  223. gis.gdal.Polygon
  224. gis.gdal.Polygon.centroid
  225. gis.gdal.Polygon.exterior_ring
  226. gis.gdal.Polygon.shell
  227. gis.gdal.SpatialReference
  228. gis.gdal.SpatialReference.__getitem__()
  229. gis.gdal.SpatialReference.angular_name
  230. gis.gdal.SpatialReference.angular_units
  231. gis.gdal.SpatialReference.attr_value()
  232. gis.gdal.SpatialReference.auth_code()
  233. gis.gdal.SpatialReference.auth_name()
  234. gis.gdal.SpatialReference.clone()
  235. gis.gdal.SpatialReference.ellipsoid
  236. gis.gdal.SpatialReference.from_esri()
  237. gis.gdal.SpatialReference.geographic
  238. gis.gdal.SpatialReference.identify_epsg()
  239. gis.gdal.SpatialReference.import_epsg()
  240. gis.gdal.SpatialReference.import_proj()
  241. gis.gdal.SpatialReference.import_user_input()
  242. gis.gdal.SpatialReference.import_wkt()
  243. gis.gdal.SpatialReference.import_xml()
  244. gis.gdal.SpatialReference.inverse_flattening
  245. gis.gdal.SpatialReference.linear_name
  246. gis.gdal.SpatialReference.linear_units
  247. gis.gdal.SpatialReference.local
  248. gis.gdal.SpatialReference.name
  249. gis.gdal.SpatialReference.pretty_wkt
  250. gis.gdal.SpatialReference.proj
  251. gis.gdal.SpatialReference.proj4
  252. gis.gdal.SpatialReference.projected
  253. gis.gdal.SpatialReference.semi_major
  254. gis.gdal.SpatialReference.semi_minor
  255. gis.gdal.SpatialReference.srid
  256. gis.gdal.SpatialReference.to_esri()
  257. gis.gdal.SpatialReference.units
  258. gis.gdal.SpatialReference.validate()
  259. gis.gdal.SpatialReference.wkt
  260. gis.gdal.SpatialReference.xml
  261. gis.geoip2.GeoIP2
  262. gis.geoip2.GeoIP2.city()
  263. gis.geoip2.GeoIP2.coords()
  264. gis.geoip2.GeoIP2.country()
  265. gis.geoip2.GeoIP2.country_code()
  266. gis.geoip2.GeoIP2.country_name()
  267. gis.geoip2.GeoIP2.geos()
  268. gis.geoip2.GeoIP2.lat_lon()
  269. gis.geoip2.GeoIP2.lon_lat()
  270. gis.geoip2.GeoIP2.open()
  271. gis.db.models.Collect
  272. gis.db.models.Extent
  273. gis.db.models.Extent3D
  274. gis.db.models.MakeLine
  275. gis.db.models.Union
  276. gis.geos.GEOSGeometry
  277. gis.geos.GEOSGeometry.area
  278. gis.geos.GEOSGeometry.boundary
  279. gis.geos.GEOSGeometry.buffer()
  280. gis.geos.GEOSGeometry.buffer_with_style()
  281. gis.geos.GEOSGeometry.centroid
  282. gis.geos.GEOSGeometry.clone()
  283. gis.geos.GEOSGeometry.contains()
  284. gis.geos.GEOSGeometry.convex_hull
  285. gis.geos.GEOSGeometry.coords
  286. gis.geos.GEOSGeometry.covers()
  287. gis.geos.GEOSGeometry.crosses()
  288. gis.geos.GEOSGeometry.difference()
  289. gis.geos.GEOSGeometry.dims
  290. gis.geos.GEOSGeometry.disjoint()
  291. gis.geos.GEOSGeometry.distance()
  292. gis.geos.GEOSGeometry.empty
  293. gis.geos.GEOSGeometry.envelope
  294. gis.geos.GEOSGeometry.equals()
  295. gis.geos.GEOSGeometry.equals_exact()
  296. gis.geos.GEOSGeometry.ewkb
  297. gis.geos.GEOSGeometry.ewkt
  298. gis.geos.GEOSGeometry.extent
  299. gis.geos.GEOSGeometry.from_gml()
  300. gis.geos.GEOSGeometry.geojson
  301. gis.geos.GEOSGeometry.geom_type
  302. gis.geos.GEOSGeometry.geom_typeid
  303. gis.geos.GEOSGeometry.hasz
  304. gis.geos.GEOSGeometry.hex
  305. gis.geos.GEOSGeometry.hexewkb
  306. gis.geos.GEOSGeometry.interpolate()
  307. gis.geos.GEOSGeometry.interpolate_normalized()
  308. gis.geos.GEOSGeometry.intersection()
  309. gis.geos.GEOSGeometry.intersects()
  310. gis.geos.GEOSGeometry.json
  311. gis.geos.GEOSGeometry.kml
  312. gis.geos.GEOSGeometry.length
  313. gis.geos.GEOSGeometry.make_valid()
  314. gis.geos.GEOSGeometry.normalize()
  315. gis.geos.GEOSGeometry.num_coords
  316. gis.geos.GEOSGeometry.num_geom
  317. gis.geos.GEOSGeometry.ogr
  318. gis.geos.GEOSGeometry.overlaps()
  319. gis.geos.GEOSGeometry.point_on_surface
  320. gis.geos.GEOSGeometry.prepared
  321. gis.geos.GEOSGeometry.project()
  322. gis.geos.GEOSGeometry.project_normalized()
  323. gis.geos.GEOSGeometry.relate()
  324. gis.geos.GEOSGeometry.relate_pattern()
  325. gis.geos.GEOSGeometry.ring
  326. gis.geos.GEOSGeometry.simple
  327. gis.geos.GEOSGeometry.simplify()
  328. gis.geos.GEOSGeometry.srid
  329. gis.geos.GEOSGeometry.srs
  330. gis.geos.GEOSGeometry.sym_difference()
  331. gis.geos.GEOSGeometry.touches()
  332. gis.geos.GEOSGeometry.transform()
  333. gis.geos.GEOSGeometry.unary_union
  334. gis.geos.GEOSGeometry.union()
  335. gis.geos.GEOSGeometry.valid
  336. gis.geos.GEOSGeometry.valid_reason
  337. gis.geos.GEOSGeometry.within()
  338. gis.geos.GEOSGeometry.wkb
  339. gis.geos.GEOSGeometry.wkt
  340. gis.geos.GeometryCollection
  341. gis.geos.LineString
  342. gis.geos.LineString.closed
  343. gis.geos.LinearRing
  344. gis.geos.LinearRing.is_counterclockwise
  345. gis.geos.MultiLineString
  346. gis.geos.MultiLineString.closed
  347. gis.geos.MultiLineString.merged
  348. gis.geos.MultiPoint
  349. gis.geos.MultiPolygon
  350. gis.geos.Point
  351. gis.geos.Polygon
  352. gis.geos.Polygon.from_bbox()
  353. gis.geos.Polygon.num_interior_rings
  354. gis.geos.PreparedGeometry
  355. gis.geos.PreparedGeometry.contains()
  356. gis.geos.PreparedGeometry.contains_properly()
  357. gis.geos.PreparedGeometry.covers()
  358. gis.geos.PreparedGeometry.crosses()
  359. gis.geos.PreparedGeometry.disjoint()
  360. gis.geos.PreparedGeometry.intersects()
  361. gis.geos.PreparedGeometry.overlaps()
  362. gis.geos.PreparedGeometry.touches()
  363. gis.geos.PreparedGeometry.within()
  364. gis.geos.WKBReader
  365. gis.geos.WKBWriter
  366. gis.geos.WKBWriter.byteorder
  367. gis.geos.WKBWriter.outdim
  368. gis.geos.WKBWriter.srid
  369. gis.geos.WKBWriter.write()
  370. gis.geos.WKBWriter.write_hex()
  371. gis.geos.WKTReader
  372. gis.geos.WKTWriter
  373. gis.geos.WKTWriter.outdim
  374. gis.geos.WKTWriter.precision
  375. gis.geos.WKTWriter.trim
  376. gis.geos.WKTWriter.write()
  377. gis.geos.fromfile()
  378. gis.geos.fromstr()
  379. gis.utils.LayerMapping
  380. gis.utils.LayerMapping.save()
  381. gis.measure.A
  382. gis.measure.Area
  383. gis.measure.Area.__getattr__()
  384. gis.measure.Area.unit_attname()
  385. gis.measure.D
  386. gis.measure.Distance
  387. gis.measure.Distance.__getattr__()
  388. gis.measure.Distance.unit_attname()
  389. gis.db.models.BaseSpatialField.spatial_index
  390. gis.db.models.BaseSpatialField.srid
  391. gis.db.models.GeometryCollectionField
  392. gis.db.models.GeometryField
  393. gis.db.models.GeometryField.dim
  394. gis.db.models.GeometryField.geography
  395. gis.db.models.LineStringField
  396. gis.db.models.MultiLineStringField
  397. gis.db.models.MultiPointField
  398. gis.db.models.MultiPolygonField
  399. gis.db.models.PointField
  400. gis.db.models.PolygonField
  401. gis.db.models.RasterField
  402. gis.utils.mapping()

How-tos

  1. Как аутентифицироваться с помощью REMOTE_USER
  2. Как использовать защиту от CSRF в Django
  3. Как написать пользовательский класс хранения
  4. Как писать пользовательские поисковые запросы
  5. Как создавать пользовательские команды django-admin
  6. Как создать пользовательские поля модели
  7. Как реализовать бэкенд пользовательского шаблона
  8. Как создавать пользовательские теги и фильтры шаблонов
  9. Как использовать Django с Дафни.
  10. Как использовать Django с Hypercorn
  11. Как развернуть с помощью ASGI
  12. Как использовать Django с Uvicorn.
  13. Deployment checklist
  14. Как развернуть Django
  15. Как аутентифицироваться в базе данных пользователей Django из Apache
  16. Как использовать «Джанго» с «Гуникорн».
  17. Как развернуть с WSGI
  18. Как использовать Django с Apache и mod_wsgi
  19. Как использовать Django с uWSGI
  20. Как управлять отчетами об ошибках
  21. “How-to” guides
  22. Как предоставить исходные данные для моделей
  23. Как интегрировать Django с унаследованной базой данных
  24. Как настроить и использовать протоколирование
  25. Как создать выходной файл CSV
  26. Как создавать файлы PDF
  27. Как переопределить шаблоны
  28. Как развернуть статические файлы
  29. Как управлять статическими файлами (например,изображениями,JavaScript,CSS)
  30. Как обновить Django до более новой версии
  31. Как установить Django на Windows
  32. Как создавать миграции баз данных

http

  1. http.FileResponse
  2. http.FileResponse.set_headers()
  3. http.HttpRequest
  4. http.HttpRequest.COOKIES
  5. http.HttpRequest.FILES
  6. http.HttpRequest.GET
  7. http.HttpRequest.META
  8. http.HttpRequest.POST
  9. http.HttpRequest.__iter__()
  10. http.HttpRequest.accepts()
  11. http.HttpRequest.body
  12. http.HttpRequest.build_absolute_uri()
  13. http.HttpRequest.content_params
  14. http.HttpRequest.content_type
  15. http.HttpRequest.current_app
  16. http.HttpRequest.encoding
  17. http.HttpRequest.exception_reporter_class
  18. http.HttpRequest.exception_reporter_filter
  19. http.HttpRequest.get_full_path()
  20. http.HttpRequest.get_full_path_info()
  21. http.HttpRequest.get_host()
  22. http.HttpRequest.get_port()
  23. http.HttpRequest.get_signed_cookie()
  24. http.HttpRequest.headers
  25. http.HttpRequest.is_secure()
  26. http.HttpRequest.method
  27. http.HttpRequest.path
  28. http.HttpRequest.path_info
  29. http.HttpRequest.read()
  30. http.HttpRequest.readline()
  31. http.HttpRequest.readlines()
  32. http.HttpRequest.resolver_match
  33. http.HttpRequest.scheme
  34. http.HttpRequest.session
  35. http.HttpRequest.site
  36. http.HttpRequest.urlconf
  37. http.HttpRequest.user
  38. http.HttpResponse
  39. http.HttpResponse.__delitem__()
  40. http.HttpResponse.__getitem__()
  41. http.HttpResponse.__init__()
  42. http.HttpResponse.__setitem__()
  43. http.HttpResponse.charset
  44. http.HttpResponse.close()
  45. http.HttpResponse.closed
  46. http.HttpResponse.content
  47. http.HttpResponse.delete_cookie()
  48. http.HttpResponse.flush()
  49. http.HttpResponse.get()
  50. http.HttpResponse.getvalue()
  51. http.HttpResponse.has_header()
  52. http.HttpResponse.headers
  53. http.HttpResponse.items()
  54. http.HttpResponse.readable()
  55. http.HttpResponse.reason_phrase
  56. http.HttpResponse.seekable()
  57. http.HttpResponse.set_cookie()
  58. http.HttpResponse.set_signed_cookie()
  59. http.HttpResponse.setdefault()
  60. http.HttpResponse.status_code
  61. http.HttpResponse.streaming
  62. http.HttpResponse.tell()
  63. http.HttpResponse.writable()
  64. http.HttpResponse.write()
  65. http.HttpResponse.writelines()
  66. http.HttpResponseBadRequest
  67. http.HttpResponseBase
  68. http.HttpResponseForbidden
  69. http.HttpResponseGone
  70. http.HttpResponseNotAllowed
  71. http.HttpResponseNotFound
  72. http.HttpResponseNotModified
  73. http.HttpResponsePermanentRedirect
  74. http.HttpResponseRedirect
  75. http.HttpResponseRedirect.url
  76. http.HttpResponseServerError
  77. http.JsonResponse
  78. http.QueryDict
  79. http.QueryDict.__contains__()
  80. http.QueryDict.__getitem__()
  81. http.QueryDict.__init__()
  82. http.QueryDict.__setitem__()
  83. http.QueryDict.appendlist()
  84. http.QueryDict.copy()
  85. http.QueryDict.dict()
  86. http.QueryDict.fromkeys()
  87. http.QueryDict.get()
  88. http.QueryDict.getlist()
  89. http.QueryDict.items()
  90. http.QueryDict.lists()
  91. http.QueryDict.pop()
  92. http.QueryDict.popitem()
  93. http.QueryDict.setdefault()
  94. http.QueryDict.setlist()
  95. http.QueryDict.setlistdefault()
  96. http.QueryDict.update()
  97. http.QueryDict.urlencode()
  98. http.QueryDict.values()
  99. http.StreamingHttpResponse
  100. http.StreamingHttpResponse.reason_phrase
  101. http.StreamingHttpResponse.status_code
  102. http.StreamingHttpResponse.streaming
  103. http.StreamingHttpResponse.streaming_content
  104. http.Http404

messages

  1. messages.add_message()
  2. messages.get_messages()
  3. messages.storage.base.BaseStorage
  4. messages.storage.base.Message
  5. messages.storage.cookie.CookieStorage
  6. messages.storage.fallback.FallbackStorage
  7. messages.storage.session.SessionStorage
  8. messages.views.SuccessMessageMixin
  9. messages.views.SuccessMessageMixin.get_success_message()
  10. messages.middleware.MessageMiddleware

middleware

  1. middleware.cache.FetchFromCacheMiddleware
  2. middleware.cache.UpdateCacheMiddleware
  3. middleware.clickjacking.XFrameOptionsMiddleware
  4. middleware.common.BrokenLinkEmailsMiddleware
  5. middleware.common.CommonMiddleware
  6. middleware.common.CommonMiddleware.response_redirect_class
  7. middleware.csrf.CsrfViewMiddleware
  8. middleware.gzip.GZipMiddleware
  9. middleware.http.ConditionalGetMiddleware
  10. middleware.locale.LocaleMiddleware
  11. middleware.locale.LocaleMiddleware.response_redirect_class
  12. middleware.security.SecurityMiddleware

postgres

  1. postgres.aggregates.ArrayAgg
  2. postgres.aggregates.ArrayAgg.distinct
  3. postgres.aggregates.ArrayAgg.ordering
  4. postgres.aggregates.BitAnd
  5. postgres.aggregates.BitOr
  6. postgres.aggregates.BitXor
  7. postgres.aggregates.BoolAnd
  8. postgres.aggregates.BoolOr
  9. postgres.aggregates.Corr
  10. postgres.aggregates.CovarPop
  11. postgres.aggregates.CovarPop.sample
  12. postgres.aggregates.JSONBAgg
  13. postgres.aggregates.JSONBAgg.distinct
  14. postgres.aggregates.JSONBAgg.ordering
  15. postgres.aggregates.RegrAvgX
  16. postgres.aggregates.RegrAvgY
  17. postgres.aggregates.RegrCount
  18. postgres.aggregates.RegrIntercept
  19. postgres.aggregates.RegrR2
  20. postgres.aggregates.RegrSXX
  21. postgres.aggregates.RegrSXY
  22. postgres.aggregates.RegrSYY
  23. postgres.aggregates.RegrSlope
  24. postgres.aggregates.StringAgg
  25. postgres.aggregates.StringAgg.delimiter
  26. postgres.aggregates.StringAgg.distinct
  27. postgres.aggregates.StringAgg.ordering
  28. postgres.constraints.ExclusionConstraint
  29. postgres.constraints.ExclusionConstraint.condition
  30. postgres.constraints.ExclusionConstraint.deferrable
  31. postgres.constraints.ExclusionConstraint.expressions
  32. postgres.constraints.ExclusionConstraint.include
  33. postgres.constraints.ExclusionConstraint.index_type
  34. postgres.constraints.ExclusionConstraint.name
  35. postgres.constraints.ExclusionConstraint.opclasses
  36. postgres.expressions.ArraySubquery
  37. postgres.fields.ArrayField
  38. postgres.fields.ArrayField.base_field
  39. postgres.fields.ArrayField.size
  40. postgres.fields.BigIntegerRangeField
  41. postgres.fields.CICharField
  42. postgres.fields.CIEmailField
  43. postgres.fields.CIText
  44. postgres.fields.CITextField
  45. postgres.fields.DateRangeField
  46. postgres.fields.DateTimeRangeField
  47. postgres.fields.DateTimeRangeField.default_bounds
  48. postgres.fields.DecimalRangeField
  49. postgres.fields.DecimalRangeField.default_bounds
  50. postgres.fields.HStoreField
  51. postgres.fields.IntegerRangeField
  52. postgres.fields.RangeBoundary
  53. postgres.fields.RangeBoundary.inclusive_lower
  54. postgres.fields.RangeBoundary.inclusive_upper
  55. postgres.fields.RangeField
  56. postgres.fields.RangeField.base_field
  57. postgres.fields.RangeField.form_field
  58. postgres.fields.RangeField.range_type
  59. postgres.fields.RangeOperators
  60. postgres.fields.django.postgres.forms.BaseRangeField
  61. postgres.fields.django.postgres.forms.BaseRangeField.base_field
  62. postgres.fields.django.postgres.forms.BaseRangeField.range_type
  63. postgres.fields.hstore.KeyTransform
  64. postgres.forms.DateRangeField
  65. postgres.forms.DateTimeRangeField
  66. postgres.forms.DecimalRangeField
  67. postgres.forms.HStoreField
  68. postgres.forms.IntegerRangeField
  69. postgres.forms.RangeWidget
  70. postgres.forms.RangeWidget.base_widget
  71. postgres.forms.RangeWidget.decompress()
  72. postgres.forms.SimpleArrayField
  73. postgres.forms.SimpleArrayField.base_field
  74. postgres.forms.SimpleArrayField.delimiter
  75. postgres.forms.SimpleArrayField.max_length
  76. postgres.forms.SimpleArrayField.min_length
  77. postgres.forms.SplitArrayField
  78. postgres.forms.SplitArrayField.base_field
  79. postgres.forms.SplitArrayField.remove_trailing_nulls
  80. postgres.forms.SplitArrayField.size
  81. postgres.functions.RandomUUID
  82. postgres.functions.TransactionNow
  83. postgres.indexes.BTreeIndex
  84. postgres.indexes.BloomIndex
  85. postgres.indexes.BrinIndex
  86. postgres.indexes.GinIndex
  87. postgres.indexes.GistIndex
  88. postgres.indexes.HashIndex
  89. postgres.indexes.OpClass
  90. postgres.indexes.SpGistIndex
  91. postgres.operations.AddConstraintNotValid
  92. postgres.operations.AddIndexConcurrently
  93. postgres.operations.BloomExtension
  94. postgres.operations.BtreeGinExtension
  95. postgres.operations.BtreeGistExtension
  96. postgres.operations.CITextExtension
  97. postgres.operations.CreateCollation
  98. postgres.operations.CreateExtension
  99. postgres.operations.CreateExtension.name
  100. postgres.operations.CryptoExtension
  101. postgres.operations.HStoreExtension
  102. postgres.operations.RemoveCollation
  103. postgres.operations.RemoveIndexConcurrently
  104. postgres.operations.TrigramExtension
  105. postgres.operations.UnaccentExtension
  106. postgres.operations.ValidateConstraint
  107. postgres.search.SearchHeadline
  108. postgres.search.SearchQuery
  109. postgres.search.SearchRank
  110. postgres.search.SearchVector
  111. postgres.search.SearchVectorField
  112. postgres.search.TrigramDistance
  113. postgres.search.TrigramSimilarity
  114. postgres.search.TrigramWordDistance
  115. postgres.search.TrigramWordSimilarity
  116. postgres.validators.KeysValidator
  117. postgres.validators.RangeMaxValueValidator
  118. postgres.validators.RangeMinValueValidator

redirects

  1. redirects.middleware.RedirectFallbackMiddleware
  2. redirects.middleware.RedirectFallbackMiddleware.response_gone_class
  3. redirects.middleware.RedirectFallbackMiddleware.response_redirect_class
  4. redirects.models.Redirect

sessions

  1. sessions.middleware.SessionMiddleware
  2. sessions.backends.base.SessionBase
  3. sessions.backends.base.SessionBase.__contains__()
  4. sessions.backends.base.SessionBase.__delitem__()
  5. sessions.backends.base.SessionBase.__getitem__()
  6. sessions.backends.base.SessionBase.__setitem__()
  7. sessions.backends.base.SessionBase.clear()
  8. sessions.backends.base.SessionBase.clear_expired()
  9. sessions.backends.base.SessionBase.cycle_key()
  10. sessions.backends.base.SessionBase.delete_test_cookie()
  11. sessions.backends.base.SessionBase.flush()
  12. sessions.backends.base.SessionBase.get()
  13. sessions.backends.base.SessionBase.get_expire_at_browser_close()
  14. sessions.backends.base.SessionBase.get_expiry_age()
  15. sessions.backends.base.SessionBase.get_expiry_date()
  16. sessions.backends.base.SessionBase.get_session_cookie_age()
  17. sessions.backends.base.SessionBase.items()
  18. sessions.backends.base.SessionBase.keys()
  19. sessions.backends.base.SessionBase.pop()
  20. sessions.backends.base.SessionBase.set_expiry()
  21. sessions.backends.base.SessionBase.set_test_cookie()
  22. sessions.backends.base.SessionBase.setdefault()
  23. sessions.backends.base.SessionBase.test_cookie_worked()
  24. sessions.backends.cached_db.SessionStore
  25. sessions.backends.cached_db.SessionStore.cache_key_prefix
  26. sessions.backends.db.SessionStore
  27. sessions.backends.db.SessionStore.create_model_instance()
  28. sessions.backends.db.SessionStore.get_model_class()
  29. sessions.base_session.AbstractBaseSession
  30. sessions.base_session.AbstractBaseSession.expire_date
  31. sessions.base_session.AbstractBaseSession.get_decoded()
  32. sessions.base_session.AbstractBaseSession.get_session_store_class()
  33. sessions.base_session.AbstractBaseSession.session_data
  34. sessions.base_session.AbstractBaseSession.session_key
  35. sessions.base_session.BaseSessionManager
  36. sessions.base_session.BaseSessionManager.encode()
  37. sessions.base_session.BaseSessionManager.save()
  38. sessions.serializers.JSONSerializer
  39. sessions.serializers.PickleSerializer

settings

  1. settings.GDAL_LIBRARY_PATH
  2. settings.GEOIP_CITY
  3. settings.GEOIP_COUNTRY
  4. settings.GEOIP_PATH
  5. settings.GEOS_LIBRARY_PATH
  6. settings.ABSOLUTE_URL_OVERRIDES
  7. settings.ADMINS
  8. settings.ALLOWED_HOSTS
  9. settings.APPEND_SLASH
  10. settings.AUTHENTICATION_BACKENDS
  11. settings.AUTH_PASSWORD_VALIDATORS
  12. settings.AUTH_USER_MODEL
  13. settings.CACHES
  14. settings.CACHE_MIDDLEWARE_ALIAS
  15. settings.CACHE_MIDDLEWARE_KEY_PREFIX
  16. settings.CACHE_MIDDLEWARE_SECONDS
  17. settings.CSRF_COOKIE_AGE
  18. settings.CSRF_COOKIE_DOMAIN
  19. settings.CSRF_COOKIE_HTTPONLY
  20. settings.CSRF_COOKIE_MASKED
  21. settings.CSRF_COOKIE_NAME
  22. settings.CSRF_COOKIE_PATH
  23. settings.CSRF_COOKIE_SAMESITE
  24. settings.CSRF_COOKIE_SECURE
  25. settings.CSRF_FAILURE_VIEW
  26. settings.CSRF_HEADER_NAME
  27. settings.CSRF_TRUSTED_ORIGINS
  28. settings.CSRF_USE_SESSIONS
  29. settings.DATABASES
  30. settings.DATABASE_ROUTERS
  31. settings.DATA_UPLOAD_MAX_MEMORY_SIZE
  32. settings.DATA_UPLOAD_MAX_NUMBER_FIELDS
  33. settings.DATETIME_FORMAT
  34. settings.DATETIME_INPUT_FORMATS
  35. settings.DATE_FORMAT
  36. settings.DATE_INPUT_FORMATS
  37. settings.DEBUG
  38. settings.DEBUG_PROPAGATE_EXCEPTIONS
  39. settings.DECIMAL_SEPARATOR
  40. settings.DEFAULT_AUTO_FIELD
  41. settings.DEFAULT_CHARSET
  42. settings.DEFAULT_EXCEPTION_REPORTER
  43. settings.DEFAULT_EXCEPTION_REPORTER_FILTER
  44. settings.DEFAULT_FILE_STORAGE
  45. settings.DEFAULT_FROM_EMAIL
  46. settings.DEFAULT_INDEX_TABLESPACE
  47. settings.DEFAULT_TABLESPACE
  48. settings.DISALLOWED_USER_AGENTS
  49. settings.EMAIL_BACKEND
  50. settings.EMAIL_FILE_PATH
  51. settings.EMAIL_HOST
  52. settings.EMAIL_HOST_PASSWORD
  53. settings.EMAIL_HOST_USER
  54. settings.EMAIL_PORT
  55. settings.EMAIL_SSL_CERTFILE
  56. settings.EMAIL_SSL_KEYFILE
  57. settings.EMAIL_SUBJECT_PREFIX
  58. settings.EMAIL_TIMEOUT
  59. settings.EMAIL_USE_LOCALTIME
  60. settings.EMAIL_USE_SSL
  61. settings.EMAIL_USE_TLS
  62. settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS
  63. settings.FILE_UPLOAD_HANDLERS
  64. settings.FILE_UPLOAD_MAX_MEMORY_SIZE
  65. settings.FILE_UPLOAD_PERMISSIONS
  66. settings.FILE_UPLOAD_TEMP_DIR
  67. settings.FIRST_DAY_OF_WEEK
  68. settings.FIXTURE_DIRS
  69. settings.FORCE_SCRIPT_NAME
  70. settings.FORMAT_MODULE_PATH
  71. settings.FORM_RENDERER
  72. settings.IGNORABLE_404_URLS
  73. settings.INSTALLED_APPS
  74. settings.INTERNAL_IPS
  75. settings.LANGUAGES
  76. settings.LANGUAGES_BIDI
  77. settings.LANGUAGE_CODE
  78. settings.LANGUAGE_COOKIE_AGE
  79. settings.LANGUAGE_COOKIE_DOMAIN
  80. settings.LANGUAGE_COOKIE_HTTPONLY
  81. settings.LANGUAGE_COOKIE_NAME
  82. settings.LANGUAGE_COOKIE_PATH
  83. settings.LANGUAGE_COOKIE_SAMESITE
  84. settings.LANGUAGE_COOKIE_SECURE
  85. settings.LOCALE_PATHS
  86. settings.LOGGING
  87. settings.LOGGING_CONFIG
  88. settings.LOGIN_REDIRECT_URL
  89. settings.LOGIN_URL
  90. settings.LOGOUT_REDIRECT_URL
  91. settings.MANAGERS
  92. settings.MEDIA_ROOT
  93. settings.MEDIA_URL
  94. settings.MESSAGE_LEVEL
  95. settings.MESSAGE_STORAGE
  96. settings.MESSAGE_TAGS
  97. settings.MIDDLEWARE
  98. settings.MIGRATION_MODULES
  99. settings.MONTH_DAY_FORMAT
  100. settings.NUMBER_GROUPING
  101. settings.PASSWORD_HASHERS
  102. settings.PASSWORD_RESET_TIMEOUT
  103. settings.PREPEND_WWW
  104. settings.ROOT_URLCONF
  105. settings.SECRET_KEY
  106. settings.SECRET_KEY_FALLBACKS
  107. settings.SECURE_CONTENT_TYPE_NOSNIFF
  108. settings.SECURE_CROSS_ORIGIN_OPENER_POLICY
  109. settings.SECURE_HSTS_INCLUDE_SUBDOMAINS
  110. settings.SECURE_HSTS_PRELOAD
  111. settings.SECURE_HSTS_SECONDS
  112. settings.SECURE_PROXY_SSL_HEADER
  113. settings.SECURE_REDIRECT_EXEMPT
  114. settings.SECURE_REFERRER_POLICY
  115. settings.SECURE_SSL_HOST
  116. settings.SECURE_SSL_REDIRECT
  117. settings.SERIALIZATION_MODULES
  118. settings.SERVER_EMAIL
  119. settings.SESSION_CACHE_ALIAS
  120. settings.SESSION_COOKIE_AGE
  121. settings.SESSION_COOKIE_DOMAIN
  122. settings.SESSION_COOKIE_HTTPONLY
  123. settings.SESSION_COOKIE_NAME
  124. settings.SESSION_COOKIE_PATH
  125. settings.SESSION_COOKIE_SAMESITE
  126. settings.SESSION_COOKIE_SECURE
  127. settings.SESSION_ENGINE
  128. settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
  129. settings.SESSION_FILE_PATH
  130. settings.SESSION_SAVE_EVERY_REQUEST
  131. settings.SESSION_SERIALIZER
  132. settings.SHORT_DATETIME_FORMAT
  133. settings.SHORT_DATE_FORMAT
  134. settings.SIGNING_BACKEND
  135. settings.SILENCED_SYSTEM_CHECKS
  136. settings.SITE_ID
  137. settings.STATICFILES_DIRS
  138. settings.STATICFILES_FINDERS
  139. settings.STATICFILES_STORAGE
  140. settings.STATIC_ROOT
  141. settings.STATIC_URL
  142. settings.TEMPLATES
  143. settings.TEST_NON_SERIALIZED_APPS
  144. settings.TEST_RUNNER
  145. settings.THOUSAND_SEPARATOR
  146. settings.TIME_FORMAT
  147. settings.TIME_INPUT_FORMATS
  148. settings.USE_DEPRECATED_PYTZ
  149. settings.USE_I18N
  150. settings.USE_L10N
  151. settings.USE_THOUSAND_SEPARATOR
  152. settings.USE_TZ
  153. settings.USE_X_FORWARDED_HOST
  154. settings.USE_X_FORWARDED_PORT
  155. settings.WSGI_APPLICATION
  156. settings.X_FRAME_OPTIONS
  157. settings.YEAR_MONTH_FORMAT

shortcuts

  1. shortcuts.get_list_or_404()
  2. shortcuts.get_object_or_404()
  3. shortcuts.redirect()
  4. shortcuts.render()

sitemaps

  1. sitemaps.GenericSitemap
  2. sitemaps.Sitemap
  3. sitemaps.Sitemap.alternates
  4. sitemaps.Sitemap.changefreq
  5. sitemaps.Sitemap.get_latest_lastmod()
  6. sitemaps.Sitemap.i18n
  7. sitemaps.Sitemap.items
  8. sitemaps.Sitemap.languages
  9. sitemaps.Sitemap.lastmod
  10. sitemaps.Sitemap.limit
  11. sitemaps.Sitemap.location
  12. sitemaps.Sitemap.paginator
  13. sitemaps.Sitemap.priority
  14. sitemaps.Sitemap.protocol
  15. sitemaps.Sitemap.x_default
  16. sitemaps.ping_google()
  17. sitemaps.views.index()
  18. sitemaps.views.sitemap()

sites

  1. sites.managers.CurrentSiteManager
  2. sites.models.Site
  3. sites.models.Site.domain
  4. sites.models.Site.name
  5. sites.requests.RequestSite
  6. sites.requests.RequestSite.__init__()
  7. sites.shortcuts.get_current_site()
  8. sites.middleware.CurrentSiteMiddleware

staticfiles

  1. staticfiles.storage.ManifestFilesMixin
  2. staticfiles.storage.ManifestStaticFilesStorage
  3. staticfiles.storage.ManifestStaticFilesStorage.file_hash()
  4. staticfiles.storage.ManifestStaticFilesStorage.manifest_strict
  5. staticfiles.storage.ManifestStaticFilesStorage.max_post_process_passes
  6. staticfiles.storage.StaticFilesStorage
  7. staticfiles.storage.StaticFilesStorage.post_process()
  8. staticfiles.testing.StaticLiveServerTestCase
  9. staticfiles.urls.staticfiles_urlpatterns()
  10. staticfiles.views.serve()

template

  1. template.Library.filter()
  2. template.Library.inclusion_tag()
  3. template.Library.simple_tag()
  4. template.defaultfilters.stringfilter()
  5. template.response.SimpleTemplateResponse
  6. template.response.SimpleTemplateResponse.__init__()
  7. template.response.SimpleTemplateResponse.add_post_render_callback()
  8. template.response.SimpleTemplateResponse.context_data
  9. template.response.SimpleTemplateResponse.is_rendered
  10. template.response.SimpleTemplateResponse.render()
  11. template.response.SimpleTemplateResponse.rendered_content
  12. template.response.SimpleTemplateResponse.resolve_context()
  13. template.response.SimpleTemplateResponse.resolve_template()
  14. template.response.SimpleTemplateResponse.template_name
  15. template.response.TemplateResponse
  16. template.response.TemplateResponse.__init__()
  17. template.Context
  18. template.Context.flatten()
  19. template.Context.get()
  20. template.Context.pop()
  21. template.Context.push()
  22. template.Context.setdefault()
  23. template.Context.update()
  24. template.Engine
  25. template.Engine.from_string()
  26. template.Engine.get_default()
  27. template.Engine.get_template()
  28. template.Engine.select_template()
  29. template.RequestContext
  30. template.Template
  31. template.Template.render()
  32. template.base.Origin
  33. template.base.Origin.loader
  34. template.base.Origin.name
  35. template.base.Origin.template_name
  36. template.context_processors.debug()
  37. template.context_processors.i18n()
  38. template.context_processors.static()
  39. template.context_processors.tz()
  40. template.loaders.app_directories.Loader
  41. template.loaders.base.Loader
  42. template.loaders.base.Loader.get_contents()
  43. template.loaders.base.Loader.get_template()
  44. template.loaders.base.Loader.get_template_sources()
  45. template.loaders.cached.Loader
  46. template.loaders.filesystem.Loader
  47. template.loaders.locmem.Loader
  48. template.backends.base.Template.render()
  49. template.backends.django.DjangoTemplates
  50. template.backends.jinja2.Jinja2
  51. template.loader.engines
  52. template.loader.get_template()
  53. template.loader.render_to_string()
  54. template.loader.select_template()

test

  1. test.signals.setting_changed
  2. test.signals.template_rendered
  3. test.RequestFactory
  4. test.TransactionTestCase.available_apps
  5. test.TransactionTestCase.reset_sequences
  6. test.runner.DiscoverRunner
  7. test.runner.DiscoverRunner.add_arguments()
  8. test.runner.DiscoverRunner.build_suite()
  9. test.runner.DiscoverRunner.get_test_runner_kwargs()
  10. test.runner.DiscoverRunner.log()
  11. test.runner.DiscoverRunner.run_checks()
  12. test.runner.DiscoverRunner.run_suite()
  13. test.runner.DiscoverRunner.run_tests()
  14. test.runner.DiscoverRunner.setup_databases()
  15. test.runner.DiscoverRunner.setup_test_environment()
  16. test.runner.DiscoverRunner.suite_result()
  17. test.runner.DiscoverRunner.teardown_databases()
  18. test.runner.DiscoverRunner.teardown_test_environment()
  19. test.runner.DiscoverRunner.test_loader
  20. test.runner.DiscoverRunner.test_runner
  21. test.runner.DiscoverRunner.test_suite
  22. test.utils.setup_databases()
  23. test.utils.setup_test_environment()
  24. test.utils.teardown_databases()
  25. test.utils.teardown_test_environment()
  26. test.Client
  27. test.Client.cookies
  28. test.Client.delete()
  29. test.Client.force_login()
  30. test.Client.get()
  31. test.Client.head()
  32. test.Client.login()
  33. test.Client.logout()
  34. test.Client.options()
  35. test.Client.patch()
  36. test.Client.post()
  37. test.Client.put()
  38. test.Client.session
  39. test.Client.trace()
  40. test.LiveServerTestCase
  41. test.Response
  42. test.Response.client
  43. test.Response.content
  44. test.Response.context
  45. test.Response.exc_info
  46. test.Response.json()
  47. test.Response.request
  48. test.Response.resolver_match
  49. test.Response.status_code
  50. test.Response.templates
  51. test.Response.wsgi_request
  52. test.SimpleTestCase
  53. test.SimpleTestCase.assertContains()
  54. test.SimpleTestCase.assertFieldOutput()
  55. test.SimpleTestCase.assertFormError()
  56. test.SimpleTestCase.assertFormsetError()
  57. test.SimpleTestCase.assertHTMLEqual()
  58. test.SimpleTestCase.assertHTMLNotEqual()
  59. test.SimpleTestCase.assertInHTML()
  60. test.SimpleTestCase.assertJSONEqual()
  61. test.SimpleTestCase.assertJSONNotEqual()
  62. test.SimpleTestCase.assertNotContains()
  63. test.SimpleTestCase.assertRaisesMessage()
  64. test.SimpleTestCase.assertRedirects()
  65. test.SimpleTestCase.assertTemplateNotUsed()
  66. test.SimpleTestCase.assertTemplateUsed()
  67. test.SimpleTestCase.assertURLEqual()
  68. test.SimpleTestCase.assertWarnsMessage()
  69. test.SimpleTestCase.assertXMLEqual()
  70. test.SimpleTestCase.assertXMLNotEqual()
  71. test.SimpleTestCase.client
  72. test.SimpleTestCase.client_class
  73. test.SimpleTestCase.databases
  74. test.SimpleTestCase.modify_settings()
  75. test.SimpleTestCase.settings()
  76. test.TestCase
  77. test.TestCase.captureOnCommitCallbacks()
  78. test.TestCase.databases
  79. test.TestCase.setUpTestData()
  80. test.TransactionTestCase
  81. test.TransactionTestCase.assertNumQueries()
  82. test.TransactionTestCase.assertQuerysetEqual()
  83. test.TransactionTestCase.databases
  84. test.TransactionTestCase.fixtures
  85. test.modify_settings()
  86. test.override_settings()
  87. test.skipIfDBFeature()
  88. test.skipUnlessDBFeature()
  89. test.utils.isolate_apps()

urls

  1. urls.ResolverMatch
  2. urls.ResolverMatch.app_name
  3. urls.ResolverMatch.app_names
  4. urls.ResolverMatch.args
  5. urls.ResolverMatch.captured_kwargs
  6. urls.ResolverMatch.extra_kwargs
  7. urls.ResolverMatch.func
  8. urls.ResolverMatch.kwargs
  9. urls.ResolverMatch.namespace
  10. urls.ResolverMatch.namespaces
  11. urls.ResolverMatch.route
  12. urls.ResolverMatch.tried
  13. urls.ResolverMatch.url_name
  14. urls.ResolverMatch.view_name
  15. urls.get_script_prefix()
  16. urls.resolve()
  17. urls.reverse()
  18. urls.reverse_lazy()
  19. urls.include()
  20. urls.path()
  21. urls.re_path()
  22. urls.register_converter()

utils

  1. utils.log.AdminEmailHandler
  2. utils.log.AdminEmailHandler.send_mail()
  3. utils.log.CallbackFilter
  4. utils.log.RequireDebugFalse
  5. utils.log.RequireDebugTrue
  6. utils.cache.add_never_cache_headers()
  7. utils.cache.get_cache_key()
  8. utils.cache.get_max_age()
  9. utils.cache.learn_cache_key()
  10. utils.cache.patch_cache_control()
  11. utils.cache.patch_response_headers()
  12. utils.cache.patch_vary_headers()
  13. utils.dateparse.parse_date()
  14. utils.dateparse.parse_datetime()
  15. utils.dateparse.parse_duration()
  16. utils.dateparse.parse_time()
  17. utils.decorators.async_only_middleware()
  18. utils.decorators.decorator_from_middleware()
  19. utils.decorators.decorator_from_middleware_with_args()
  20. utils.decorators.method_decorator()
  21. utils.decorators.sync_and_async_middleware()
  22. utils.decorators.sync_only_middleware()
  23. utils.encoding.escape_uri_path()
  24. utils.encoding.filepath_to_uri()
  25. utils.encoding.force_bytes()
  26. utils.encoding.force_str()
  27. utils.encoding.iri_to_uri()
  28. utils.encoding.is_protected_type()
  29. utils.encoding.smart_bytes()
  30. utils.encoding.smart_str()
  31. utils.encoding.uri_to_iri()
  32. utils.feedgenerator.Atom1Feed
  33. utils.feedgenerator.Enclosure
  34. utils.feedgenerator.Rss201rev2Feed
  35. utils.feedgenerator.RssFeed
  36. utils.feedgenerator.RssUserland091Feed
  37. utils.feedgenerator.SyndicationFeed
  38. utils.feedgenerator.SyndicationFeed.__init__()
  39. utils.feedgenerator.SyndicationFeed.add_item()
  40. utils.feedgenerator.SyndicationFeed.add_item_elements()
  41. utils.feedgenerator.SyndicationFeed.add_root_elements()
  42. utils.feedgenerator.SyndicationFeed.item_attributes()
  43. utils.feedgenerator.SyndicationFeed.latest_post_date()
  44. utils.feedgenerator.SyndicationFeed.num_items()
  45. utils.feedgenerator.SyndicationFeed.root_attributes()
  46. utils.feedgenerator.SyndicationFeed.write()
  47. utils.feedgenerator.SyndicationFeed.writeString()
  48. utils.feedgenerator.get_tag_uri()
  49. utils.functional.cached_property
  50. utils.functional.classproperty
  51. utils.functional.keep_lazy()
  52. utils.functional.keep_lazy_text()
  53. utils.html.conditional_escape()
  54. utils.html.escape()
  55. utils.html.format_html()
  56. utils.html.format_html_join()
  57. utils.html.html_safe()
  58. utils.html.json_script()
  59. utils.html.strip_tags()
  60. utils.http.base36_to_int()
  61. utils.http.http_date()
  62. utils.http.int_to_base36()
  63. utils.http.urlencode()
  64. utils.http.urlsafe_base64_decode()
  65. utils.http.urlsafe_base64_encode()
  66. utils.module_loading.import_string()
  67. utils.safestring.SafeString
  68. utils.safestring.mark_safe()
  69. utils.text.format_lazy()
  70. utils.text.slugify()
  71. utils.timezone.activate()
  72. utils.timezone.deactivate()
  73. utils.timezone.get_current_timezone()
  74. utils.timezone.get_current_timezone_name()
  75. utils.timezone.get_default_timezone()
  76. utils.timezone.get_default_timezone_name()
  77. utils.timezone.get_fixed_timezone()
  78. utils.timezone.is_aware()
  79. utils.timezone.is_naive()
  80. utils.timezone.localdate()
  81. utils.timezone.localtime()
  82. utils.timezone.make_aware()
  83. utils.timezone.make_naive()
  84. utils.timezone.now()
  85. utils.timezone.override()
  86. utils.timezone.utc
  87. utils.translation.activate()
  88. utils.translation.check_for_language()
  89. utils.translation.deactivate()
  90. utils.translation.deactivate_all()
  91. utils.translation.get_language()
  92. utils.translation.get_language_bidi()
  93. utils.translation.get_language_from_request()
  94. utils.translation.get_supported_language_variant()
  95. utils.translation.gettext()
  96. utils.translation.gettext_lazy()
  97. utils.translation.gettext_noop()
  98. utils.translation.ngettext()
  99. utils.translation.ngettext_lazy()
  100. utils.translation.npgettext()
  101. utils.translation.npgettext_lazy()
  102. utils.translation.override()
  103. utils.translation.pgettext()
  104. utils.translation.pgettext_lazy()
  105. utils.translation.templatize()
  106. utils.translation.to_locale()
  107. utils.deprecation.MiddlewareMixin
  108. utils.translation.get_language_info()

views

  1. views.debug.ExceptionReporter
  2. views.debug.ExceptionReporter.get_traceback_data()
  3. views.debug.ExceptionReporter.get_traceback_html()
  4. views.debug.ExceptionReporter.get_traceback_text()
  5. views.debug.ExceptionReporter.html_template_path
  6. views.debug.ExceptionReporter.text_template_path
  7. views.debug.SafeExceptionReporterFilter
  8. views.debug.SafeExceptionReporterFilter.cleansed_substitute
  9. views.debug.SafeExceptionReporterFilter.get_post_parameters()
  10. views.debug.SafeExceptionReporterFilter.get_traceback_frame_variables()
  11. views.debug.SafeExceptionReporterFilter.hidden_settings
  12. views.debug.SafeExceptionReporterFilter.is_active()
  13. views.decorators.debug.sensitive_post_parameters()
  14. views.decorators.debug.sensitive_variables()
  15. views.generic.base.RedirectView
  16. views.generic.base.RedirectView.get_redirect_url()
  17. views.generic.base.RedirectView.pattern_name
  18. views.generic.base.RedirectView.permanent
  19. views.generic.base.RedirectView.query_string
  20. views.generic.base.RedirectView.url
  21. views.generic.base.TemplateView
  22. views.generic.base.View
  23. views.generic.base.View.as_view()
  24. views.generic.base.View.dispatch()
  25. views.generic.base.View.http_method_names
  26. views.generic.base.View.http_method_not_allowed()
  27. views.generic.base.View.options()
  28. views.generic.base.View.setup()
  29. views.generic.dates.ArchiveIndexView
  30. views.generic.dates.BaseArchiveIndexView
  31. views.generic.dates.BaseDateDetailView
  32. views.generic.dates.BaseDayArchiveView
  33. views.generic.dates.BaseMonthArchiveView
  34. views.generic.dates.BaseTodayArchiveView
  35. views.generic.dates.BaseWeekArchiveView
  36. views.generic.dates.BaseYearArchiveView
  37. views.generic.dates.DateDetailView
  38. views.generic.dates.DayArchiveView
  39. views.generic.dates.MonthArchiveView
  40. views.generic.dates.TodayArchiveView
  41. views.generic.dates.WeekArchiveView
  42. views.generic.dates.YearArchiveView
  43. views.generic.dates.YearArchiveView.get_make_object_list()
  44. views.generic.dates.YearArchiveView.make_object_list
  45. views.generic.detail.BaseDetailView
  46. views.generic.detail.BaseDetailView.get()
  47. views.generic.detail.DetailView
  48. views.generic.list.BaseListView
  49. views.generic.list.BaseListView.get()
  50. views.generic.list.ListView
  51. views.generic.edit.BaseCreateView
  52. views.generic.edit.BaseCreateView.get()
  53. views.generic.edit.BaseCreateView.post()
  54. views.generic.edit.BaseDeleteView
  55. views.generic.edit.BaseFormView
  56. views.generic.edit.BaseUpdateView
  57. views.generic.edit.BaseUpdateView.get()
  58. views.generic.edit.BaseUpdateView.post()
  59. views.generic.edit.CreateView
  60. views.generic.edit.CreateView.object
  61. views.generic.edit.CreateView.template_name_suffix
  62. views.generic.edit.DeleteView
  63. views.generic.edit.DeleteView.form_class
  64. views.generic.edit.DeleteView.template_name_suffix
  65. views.generic.edit.FormView
  66. views.generic.edit.UpdateView
  67. views.generic.edit.UpdateView.object
  68. views.generic.edit.UpdateView.template_name_suffix
  69. views.generic.dates.BaseDateListView
  70. views.generic.dates.BaseDateListView.allow_empty
  71. views.generic.dates.BaseDateListView.date_list_period
  72. views.generic.dates.BaseDateListView.get_date_list()
  73. views.generic.dates.BaseDateListView.get_date_list_period()
  74. views.generic.dates.BaseDateListView.get_dated_items()
  75. views.generic.dates.BaseDateListView.get_dated_queryset()
  76. views.generic.dates.DateMixin
  77. views.generic.dates.DateMixin.allow_future
  78. views.generic.dates.DateMixin.date_field
  79. views.generic.dates.DateMixin.get_allow_future()
  80. views.generic.dates.DateMixin.get_date_field()
  81. views.generic.dates.DayMixin
  82. views.generic.dates.DayMixin.day
  83. views.generic.dates.DayMixin.day_format
  84. views.generic.dates.DayMixin.get_day()
  85. views.generic.dates.DayMixin.get_day_format()
  86. views.generic.dates.DayMixin.get_next_day()
  87. views.generic.dates.DayMixin.get_previous_day()
  88. views.generic.dates.MonthMixin
  89. views.generic.dates.MonthMixin.get_month()
  90. views.generic.dates.MonthMixin.get_month_format()
  91. views.generic.dates.MonthMixin.get_next_month()
  92. views.generic.dates.MonthMixin.get_previous_month()
  93. views.generic.dates.MonthMixin.month
  94. views.generic.dates.MonthMixin.month_format
  95. views.generic.dates.WeekMixin
  96. views.generic.dates.WeekMixin.get_next_week()
  97. views.generic.dates.WeekMixin.get_prev_week()
  98. views.generic.dates.WeekMixin.get_week()
  99. views.generic.dates.WeekMixin.get_week_format()
  100. views.generic.dates.WeekMixin.week
  101. views.generic.dates.WeekMixin.week_format
  102. views.generic.dates.YearMixin
  103. views.generic.dates.YearMixin.get_next_year()
  104. views.generic.dates.YearMixin.get_previous_year()
  105. views.generic.dates.YearMixin.get_year()
  106. views.generic.dates.YearMixin.get_year_format()
  107. views.generic.dates.YearMixin.year
  108. views.generic.dates.YearMixin.year_format
  109. views.generic.edit.DeletionMixin
  110. views.generic.edit.DeletionMixin.delete()
  111. views.generic.edit.DeletionMixin.get_success_url()
  112. views.generic.edit.DeletionMixin.success_url
  113. views.generic.edit.FormMixin
  114. views.generic.edit.FormMixin.form_class
  115. views.generic.edit.FormMixin.form_invalid()
  116. views.generic.edit.FormMixin.form_valid()
  117. views.generic.edit.FormMixin.get_context_data()
  118. views.generic.edit.FormMixin.get_form()
  119. views.generic.edit.FormMixin.get_form_class()
  120. views.generic.edit.FormMixin.get_form_kwargs()
  121. views.generic.edit.FormMixin.get_initial()
  122. views.generic.edit.FormMixin.get_prefix()
  123. views.generic.edit.FormMixin.get_success_url()
  124. views.generic.edit.FormMixin.initial
  125. views.generic.edit.FormMixin.prefix
  126. views.generic.edit.FormMixin.success_url
  127. views.generic.edit.ModelFormMixin
  128. views.generic.edit.ModelFormMixin.fields
  129. views.generic.edit.ModelFormMixin.form_invalid()
  130. views.generic.edit.ModelFormMixin.form_valid()
  131. views.generic.edit.ModelFormMixin.get_form_class()
  132. views.generic.edit.ModelFormMixin.get_form_kwargs()
  133. views.generic.edit.ModelFormMixin.get_success_url()
  134. views.generic.edit.ModelFormMixin.model
  135. views.generic.edit.ModelFormMixin.success_url
  136. views.generic.edit.ProcessFormView
  137. views.generic.edit.ProcessFormView.get()
  138. views.generic.edit.ProcessFormView.post()
  139. views.generic.edit.ProcessFormView.put()
  140. views.generic.list.MultipleObjectMixin
  141. views.generic.list.MultipleObjectMixin.allow_empty
  142. views.generic.list.MultipleObjectMixin.context_object_name
  143. views.generic.list.MultipleObjectMixin.get_allow_empty()
  144. views.generic.list.MultipleObjectMixin.get_context_data()
  145. views.generic.list.MultipleObjectMixin.get_context_object_name()
  146. views.generic.list.MultipleObjectMixin.get_ordering()
  147. views.generic.list.MultipleObjectMixin.get_paginate_by()
  148. views.generic.list.MultipleObjectMixin.get_paginate_orphans()
  149. views.generic.list.MultipleObjectMixin.get_paginator()
  150. views.generic.list.MultipleObjectMixin.get_queryset()
  151. views.generic.list.MultipleObjectMixin.model
  152. views.generic.list.MultipleObjectMixin.ordering
  153. views.generic.list.MultipleObjectMixin.page_kwarg
  154. views.generic.list.MultipleObjectMixin.paginate_by
  155. views.generic.list.MultipleObjectMixin.paginate_orphans
  156. views.generic.list.MultipleObjectMixin.paginate_queryset()
  157. views.generic.list.MultipleObjectMixin.paginator_class
  158. views.generic.list.MultipleObjectMixin.queryset
  159. views.generic.list.MultipleObjectTemplateResponseMixin
  160. views.generic.list.MultipleObjectTemplateResponseMixin.get_template_names()
  161. views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix
  162. views.generic.base.ContextMixin
  163. views.generic.base.ContextMixin.extra_context
  164. views.generic.base.ContextMixin.get_context_data()
  165. views.generic.base.TemplateResponseMixin
  166. views.generic.base.TemplateResponseMixin.content_type
  167. views.generic.base.TemplateResponseMixin.get_template_names()
  168. views.generic.base.TemplateResponseMixin.render_to_response()
  169. views.generic.base.TemplateResponseMixin.response_class
  170. views.generic.base.TemplateResponseMixin.template_engine
  171. views.generic.base.TemplateResponseMixin.template_name
  172. views.generic.detail.SingleObjectMixin
  173. views.generic.detail.SingleObjectMixin.context_object_name
  174. views.generic.detail.SingleObjectMixin.get_context_data()
  175. views.generic.detail.SingleObjectMixin.get_context_object_name()
  176. views.generic.detail.SingleObjectMixin.get_object()
  177. views.generic.detail.SingleObjectMixin.get_queryset()
  178. views.generic.detail.SingleObjectMixin.get_slug_field()
  179. views.generic.detail.SingleObjectMixin.model
  180. views.generic.detail.SingleObjectMixin.pk_url_kwarg
  181. views.generic.detail.SingleObjectMixin.query_pk_and_slug
  182. views.generic.detail.SingleObjectMixin.queryset
  183. views.generic.detail.SingleObjectMixin.slug_field
  184. views.generic.detail.SingleObjectMixin.slug_url_kwarg
  185. views.generic.detail.SingleObjectTemplateResponseMixin
  186. views.generic.detail.SingleObjectTemplateResponseMixin.get_template_names()
  187. views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field
  188. views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix
  189. views.decorators.csrf.csrf_exempt()
  190. views.decorators.csrf.csrf_protect()
  191. views.decorators.csrf.ensure_csrf_cookie()
  192. views.decorators.csrf.requires_csrf_token()
  193. views.defaults.bad_request()
  194. views.defaults.page_not_found()
  195. views.defaults.permission_denied()
  196. views.defaults.server_error()
  197. views.static.serve()
  198. views.decorators.cache.cache_page()
  199. views.decorators.cache.cache_control()
  200. views.decorators.cache.never_cache()
  201. views.decorators.common.no_append_slash()
  202. views.decorators.gzip.gzip_page()
  203. views.decorators.http.condition()
  204. views.decorators.http.etag()
  205. views.decorators.http.last_modified()
  206. views.decorators.http.require_GET()
  207. views.decorators.http.require_POST()
  208. views.decorators.http.require_http_methods()
  209. views.decorators.http.require_safe()
  210. views.decorators.vary.vary_on_cookie()
  211. views.decorators.vary.vary_on_headers()
  212. views.i18n.JSONCatalog
  213. views.i18n.JavaScriptCatalog
  214. views.i18n.JavaScriptCatalog.domain
  215. views.i18n.JavaScriptCatalog.packages
  216. views.i18n.set_language()

Intro

  1. Пишите свой первый патч для Джанго.
  2. Getting started
  3. Краткое руководство по установке
  4. Джанго с первого взгляда
  5. Продвинутое учебное пособие:Как писать многоразовые приложения
  6. Написание твоего первого приложения «Джанго»,часть 1.
  7. Написание твоего первого приложения «Джанго»,часть 2.
  8. Написание твоего первого приложения «Джанго»,часть 3.
  9. Написание твоего первого приложения «Джанго»,часть 4.
  10. Написание твоего первого приложения «Джанго»,часть 5.
  11. Написание твоего первого приложения «Джанго»,часть 6.
  12. Написание твоего первого приложения «Джанго»,часть 7.


Работаем с джанго-формами. Часть 1

Работаем с джанго-формами. Часть 2

Работаем с джанго-формами. Часть 3

Работаем с джанго-формами. Часть 4

Работаем с джанго-формами. Часть 5

Привет!
Чтобы лучше усвоить работу с джанго-формами, реализуем небольшой проект.

Легенда такая. Вы — начинающий бэкендер, которого подключили к проекту создания сайта для заказа космических путешествий.
Часть бэка уже написана, есть фронт главной страницы. Как раз на этой стадии подключаетесь вы.

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

Важный момент 1: материал устроен так, что ничего (по крайней мере сейчас, у себя на машине запускать не нужно). Весь необходимый код я опишу здесь же.
В идеале, всё должно быть понятно из текста.

Если нет, пожалуйста, пишите в комментариях вопросы/пожелания/замечания, буду дорабатывать. Если всё пойдёт по плану, то получится прекрасное подспорье для будущих бэкендеров, а мечта именно такая.

Важный момент 2: этот мини-проект я делаю, по сути, сейчас вместе с вами, поэтому полной заготовки на гитхабе нет.
По мере прохождения и обсуждения проекта будет расти и код проекта в репозитории.

Репозиторий проекта

Важный момент 3: проект сугубо учебный. Он вряд ли ощутимо пополнит ваше портфолио для потенциальных работодателей, но за то ощутимо прокачает в понимании джанго и максимально осознанном (это главное!) применении инструментов фреймворка.

Поехали!

Работаем с джанго-формами. Часть 1

Какова общая логика сайта?

Пока все очень скромно:

  • клиент открывает главную страницу
  • оттуда переходит на страницу с формой заказа. Там он должен выбрать:
    • корабль, на котором хочет полететь
    • дату полета (не раньше чем через месяц после текущей даты)
    • выбрать валюту платежа (пока доступны только доллары США и российские рубли)
  • после выбора всех указанных опций он кликает на кнопку «Оформить». Важная деталь: если все места на выбранный корабль и выбранную дату исчерпаны, должно появляться информация об этом с просьбой перезаполнить форму.
  • если всё прошло штатно, то клиенту должна открыться следующая страница для завершения оформления заказа:
    • должна отображаться стоимость полета, исходя из ранее введененных данных.
      Сейчас стоимость определена в долларах, поэтому если клиент выбрал в качестве валюты рубли, надо конвертировать стоимость в рубли и показать ее по курсу на сегодня (разумеется, с сайта ЦБ).
      Но в базу все равно должно сохраниться значение в долларах.
    • введет свои имя и фамилию
    • адрес электронной почты
    • нажимает на кнопку «Поехали!», после чего заказ сохраняется в базе данных.

Что есть сейчас?

  • описаны модели
  • подключена админка
  • база заполнена данными о кораблях
  • открывается главная страница, в ссылке на страницу перехода к форме оформления заказа пока стоит заглушка.
    image

С чего начинаем?

Нужна вот такая форма для получения данных
image

Необходимые для формы данные нужно получать из БД (кроме валюты платежа).

Шаг 1. Создать страницу, на которой будет располагатся форма выбора корабля, даты полета и валюты платежа

В конце концов, мы же где-то должны показать эту форму :)

Что нужно:

  • решить, куда положить файл с новой страницей
  • создать html-файл с минимально необходимой разметкой
  • на странице сделать заготовку для формы

1.1. Решить, куда положить шаблон с новой страницей

Джанго ищет шаблоны страниц не рандомно, а во вполне конкретных местах.
Что это за места оговоривают в настройках проекта — settings.py, константа TEMPLATES.

Смотрю, что там:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [ BASE_DIR / 'templates' ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Собственно, интересуют два ключа: APP_DIRS и DIRS.
'APP_DIRS': True. Ага, значит, шаблоны можно хранить в папкаx templates внутри приложений проекта.

'DIRS': [ BASE_DIR / 'templates' ]. Так, ещё можно поместить шаблоны страницу в папку templates внутри BASE_DIR.
Поищем в настройках, что за путь у BASE_DIR (внимание: это дефолтный путь в последних версиях джанго, поэтому понимание, как это расшифровывается, пригодится везде):

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

pathlib — это стандартный (т.е. не требующий pip install ...) Python-модуль для работы с файловой системой, не важно unix или win.
Если нужно с помощью питона порыться среди своих папок и файлов, что-то создать или удалить, задать пути к тем или иным файлам, то тут либо pathlib, либо более старый (но по-прежнему актуальный) вариант с os.path (os — ещё одна стандартная Python-библиотека).

Итак, что значит Path(__file__).resolve().parent.parent
__file__ — это текущий файл, в нашем случае settings.py
Path(__file__).resolve() — построить путь к текущему файлу. В моем случае это
C:Desktopform_webinarconfigsettings.py

Чтобы более нагляднее было

form_webinar
   |
   config
   |     ├── __init__.py
   |     ├── asgi.py
   |     ├── settings.py
   |     ├── urls.py
   |     └── wsgi.py
   └──media
   |   ├── ...
   └──spaceflights
   |   ├── ...
   └──manage.py

.parent.parent — буквально означает «из текущей директории (=директории, которая является родительской для settings.py) нужно подняться в следующую директорию и взять ее путь»

Таки образом, путем для BASE_DIR будет C:Desktopform_webinar, т.е. та папка, в которой у нас лежит весь проект, та папка, из которой мы вызываем manage.py.

А BASE_DIR / 'templates' — это не что иное, как C:Desktopform_webinartemplates.

Итог. Я могу разместить шаблон страницы с формой заказа, как в папке templates внутри папок с приложениям проекта (а тут оно всего одно, назвали его spaceflights).
А могу разместить в общей папке templates в корне проекта, джанго туда тоже заглянет.

Положу в общую папку, проект маленький, да и главную страницу туда же положили. Назову новый шаблон ship.html.

1.2. Cоздать html-файл с минимально необходимой разметкой

Итак, файл создан.
image

Теперь нужно описать минимум разметки — теги html, head, body.
В VS Сode достаточно набрать в html-файле восклицательный знак (Emmet Abbreviation), появится предложение воспользоваться аббревиатурой и приняв это предложение появится необходимая разметка
и даже чуть больше

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>

Всё наше внимание на теге body, то, что в нем, пользователь увидит на странице в браузере.

1.3. На странице сделать заготовку для формы

Скелет любой html-формы — это тег form.

Создадим его внутри body.

<body>
  <form>
  </form>
</body>

Теперь нужно ответить на три вопроса:

  1. После сабмита (проще говоря, нажатия кнопки типа «Отправить»), какой контроллер («вьюха», «вью-функция») будет приводится в действие (работать с данными из формы и т.д.)?
  2. Какой url обслуживает этот контроллер (потому что задействовать мы его можем не иначе, как через обращение по урлу)?
  3. Каким http-методом — GET или POST — будут отправляться данные из формы?

Ответы на первые два вопроса нам нужны для описания атрибута actions в теге form. Атрибут actions, конечно, можно опустить, но тогда будет задействован тот же контроллер, что и отрендерил текущую страницу с формой.
Нам это не подходит, ибо ТЗ звучит так

если всё прошло штатно, то клиенту должна открыться следующая страница для завершения оформления заказа

Должен работать следующий контроллер, который будет брать данные из текущей формы и оперировать с ними в следующей форме, которая откроется на следующей странице.

Но пока такого контроллера нет (а, значит, и маршрута). Чтобы вообще не забыть об actions укажем actions="", потом допишем новый маршрут, когда сделаем новый контроллер.

Что касается третьего вопроса, то данные из формы будем передавать POST-запросом.

Итог

<body>
  <!-- дописать action, когда появится контроллер следующей формы -->
  <form action="" method="POST">
  </form>
</body>

Шаг 2. Сделать заготовку контроллера, который будет рендерить страницу с формой

Собственно говоря, для этого у нас всё есть (точнее одно-единственное — шаблон страницы, который мы положили в правильное место).
Как я уже говорил, вся логика проекта в одном приложении, spaceflights. Идём в views.py оттуда и создаём там контроллер.
image

def flight_details(request):
    return render(request, template_name='ship.html')

Так, что тут происходит:

  • контроллер принимает на вход http-запрос
  • возвращает http-ответ, который несет с собой строку со всей разметкой из файла ship.html
  • браузер считывает эту строку и отображает пользователю страницу, составленную из этой разметки

Напомню, что render из django.shortcuts, это сахарок или шорткат, функция, которая упаковывает несколько более простых действий, позволяя сократить количество кода.

Круто знать о шорткатах и писать мало кода, но ещё круче хорошо понимать, что за ними стоит.

Не используя render переписать код можно так:

from django.http import HttpResponse
from django.template import loader

def flight_details(request):
    template = loader.get_template('ship.html')
    return HttpResponse(template.render(request=request))

Кода на строчку больше, но для понимания фундамента всё гораздо яснее.
А фундамент в том, что любой контроллер в ответ на request (объект джанго-класса HttpRequest), должен возвращать объект джанго-класса HttpResponse или его наследников.

В данном случае объекту HttpResponse мы передаем шаблон, который был предварительно превращен в строку загрузчиком шаблонов. И с этой строкой дальше работает браузер.

Шаг 3. Привязать контроллер к маршруту (url) и починить ссылку с главной страницы

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

Т.е. складывается следующая цепочка: url-адрес -> контроллер -> отображение через контроллер шаблона страницы.
Мы начали с конца, т.к. без шаблона невозможен (в нашем случае) контроллер, а без контроллера маршрут.

Все маршруты приложения описываются в urls.py. Добавим туда новый:

# spaceflights/urls.py
urlpatterns = [
    ...
    path('flight/', flight_details, name='flight_details'),
]

Три аргумента для path:

  • сам маршрут (получится http://домен/flight)
  • вью-функция, которая обслуживает маршрут
  • описательное имя маршрута, чтобы потом не хардкодить ссылки на него, а пользоваться именем

Маршрут готов, его можно набирать в адресной строке браузера, но это не наш путь.
Читаем снова ТЗ:
открывается главная страница, в ссылке на страницу перехода к форме оформления заказа пока стоит заглушка.

Уберем заглушку, чтобы с главной страницы пользователь по ссылке попадал на страницу с нашей формой:

Было:

    <h2>
      <a href="#">
        Летим!
      </a>
    </h2>

Cтало:

    <h2>
      <a href="{% url 'flight_details' %}">
        Летим!
      </a>
    </h2>

Нам помог шаблонный тег {% url %}, мы передали ему имя маршрута из urls.py. и джанго уже сам превратит его в читаемый для браузера путь. Никакого харкода.
Но если бы захотелось бы похардкодить, то написали бы так
<a href="flight/">

Итого: подготовительный этап завершен. С главной страницы мы попадаем на отдельную страницу, которая пока пуста, но на ней есть заготовка формы.

Шаг 4. Начинаем создавать элементы формы с помощью Django

Сейчас на html-страницы наша форма обозначена так:

  <!-- дописать action, когда появится контроллер следующей формы -->
  <form action="" method="POST">
  </form>

Внутри формы нужно создать поля (теги input) разных типов (type=...), которые будут принимать данные.
Прежде чем писать html-разметку для полей самостоятельно, максимально задействуем возможности джанго. Будем управлять разметкой формы с бэкенда.

Начальный шаг для создания джанго-формы (задача которой: а) взять на себя создание части разметки на странице, б) проверить поступившие из html-формы даннные), всегда один и тот же: нужно создать python-класс у нашей формы и унаследоваться от класс джанго-форм.

Принято формы размещать отдельно от контроллеров, поэтому создадим внутри приложения spaceflights новый файл forms.py
image

Объявим класс джанго-формы, предварительно сделав необходимый импорт:

from django import forms

class OrderForm(forms.Form):
    ...

... это Python-объект ellipsis, который можно использовать аналогично заглушке pass (для самых любопытных короткая статья).

Круто, класс формы мы объявили, пока ни одного атрибута (поля) в форме нет.

Приступим к их созданию, руководствуясь ТЗ.

4.1 Первое поле: радиокнопки с выбором корабля

image

Нам нужно ответить, как минимум, на следующие вопросы (и так для каждого поля создаваемой нами Django-формы):

  1. Для какого поля в какой модели предназначены данные из конкретного поля html-формы?
  2. Как должно называться джанго-поле при рендеринге на html-страницe?
  3. Какой класс джанго-формы наиболее подходит для того, чтобы отрендерить поле в html-форме и проверить поступившие через него данные?
  4. Подходит ли нам дефолтный виджет (иначе говоря `<input type=»такой-то»…>), который использует подобранное нами поле джанго-формы?

Отвечаем на 1-й вопрос
Вся html-форма собирает данные, которые нужны для модели Order

class Order(models.Model):
    ship = models.ForeignKey(to=Spaceship, on_delete=models.CASCADE,
                             verbose_name='корабль')
    passenger = models.CharField(
        max_length=10, verbose_name='пассажир', blank=True
    )
    flight_date = models.DateField(verbose_name='дата полета')

Конкретно через поле html-формы «На чем летим» передаются данные для поля ship модели Order.

Что мы из этого вынесли
Поле в джанго-форме должно называться ship, т.к. именно это название попадет в качестве атрибута name в тег input html-формы.
Т.е. наши радиокнопки будет с тегами типа <input type=... name="ship">. Это важно, т.к. словаре с данными из POST-запроса ключами будут как раз name‘ы.
Конечно, можно как угодно назвать поле формы, но гораздо удобнее, когда не нужно каждый раз думать, по какому ключу искать данные из пришедшего запроса для конкретного поля модели.

Отвечаем на 2-й вопрос
При рендеринге поле должно называться На чем летим. За название любого поля джанго-формы отвечает атрибут label.
Если его явно не указать при объявлении поля, то лэйблом будет название поля как атрибута класса нашей джанго-формы, только с большой буквы.
Т.е. лэйблом будет Ship. Но нас это не устраивает.

Пруф из исходного кода джанго (модули forms.boundfield и forms.utils):

if self.field.label is None:
    self.label = pretty_name(name)
...

def pretty_name(name):
    """Convert 'first_name' to 'First name'."""
    if not name:
        return ''
    return name.replace('_', ' ').capitalize()

Что мы из этого вынесли
При объявлении класса поля надо явно передать ему label="На чем летим".

Отвечаем на 3-й вопрос
Какой класс джанго-формы наиболее подходит для того, чтобы отрендерить поле в html-форме и проверить поступившие через него данные?
В html-поле формы от пользователя требуется сделать выбор из нескольких вариантов, значит, среди классов полей джанго-форм нам нужно что-то с choices :)

Идём смотреть классы встроенных полей

Возможные кандидаты:

  • forms.ChoiceField
  • forms.MultipleChoiceField
  • forms.ModelChoiceField
  • forms.ModelMultipleChoiceField

Поля с multiple в названии заворачиваем сразу, перед пользователем стоит не множественный, а единственный выбор.
forms.ChoiceField нам тоже не подходит, т.к. на вход принимает самостоятельно нами созданный кортеж из двухэлементных кортежей (один элемент будет value поля, а второй будет рендерится на экране).
Нам не нужно ничего создавать, корабли берутся из связанной с моделью Order модели Spaceship.

В итоге остается поле ModelChoiceField. Почитаем о нем внимательнее в документации:

Позволяет выбор единственного объекта модели, имеет смысл при отображении внешнего ключа.

Класс, ровно то, что нам нужно, поле ship модели Order как раз поле с внешним ключом (связь один-ко-многим).

Какие у нас обязательные аргументы для этого поля? Он один queryset. Логично, ведь нужно же откуда-то брать значения для полей, из которых будет выбирать пользователь.

Единственный обязательный аргумент:
queryset
A QuerySet of model objects from which the choices for the field are derived and which is used to validate the user’s selection. It’s evaluated when the form is rendered.

Что мы из этого вынесли
Теперь внутри нашей джанго-формы мы можем объявить поле, все исходные данные у нас есть:

class OrderForm(forms.Form):
    ship = forms.ModelChoiceField(queryset=Spaceship.objects, label="На чем летим")

Отвечаем на 4-й вопрос
Подходит ли нам дефолтный виджет (иначе говоря `<input type=»такой-то»…>), который использует подобранное нами поле джанго-формы?

Виджет — это объект питоновского класса, который встраивается в поле джанго-формы и отвечает в нем за то, какой конкретно html-разметкой будет рендерится поле в шаблоне.
Поэтому, если вы хотели вводить цифры, а перед вами календарь, тут заслуга виджета (ну и разумеется поля джанго-формы, которое этот виджет использовало).

У каждого поля джанго-формы есть дефолтный виджет (что это за виджет написано в описании поля в документации). Но мы всегда можем указать наш собственный виджет.

Итак, у нас по дефолту select. А селекты и радиокнопки, как говорят в Одессе, это две большие разницы.
image

Заглянем в классы виджетов, которые доступны из коробки.
image

Название нужного нам виджета говорит само за себя: RadioSelect.

Аналогично Select, но отображается в виде списка радио кнопок

Чтобы переопределить виджет поля, класс нового виджета нужно передать в параметре widget.
В итоге код нашего поля выглядит так:

class OrderForm(forms.Form):
    ship = forms.ModelChoiceField(
        queryset=Spaceship.objects,
        label='На чем летим',
        widget=RadioSelect # переопределили виджет
    )

А отрендерено в шаблоне поле будет вот так:

<ul id="id_ship">
  <li>
    <label for="id_ship_0">
        <input type="radio" name="ship" value="1" required id="id_ship_0">
        Crew Dragon
    </label>
  </li>
  <li>
    <label for="id_ship_1">
      <input type="radio" name="ship" value="2" required id="id_ship_1">
      New Shepard
    </label>
  </li>
  <li>
    <label for="id_ship_2">
      <input type="radio" name="ship" value="3" required id="id_ship_2">
      VSS Unity
    </label>
  </li>
</ul>

Всё как и обещал джанго — радиокнопки (<input type="radio"...>), обернутые в маркированный список (теги ul, li).
image

Уже ощутимый результат.
Теперь нам нужно избавиться от черных маркеров (а может и вообще от тегов списка), а еще рядом с радиокнопками выводить релевантные картинки (те, которые привязаны в базе к конкретному кораблю).
Этим мы займемся в следующий раз.

Остановка, чтобы осмотреться под капотом

НЕ обязательный раздел, можно почитать, если есть время. Цель — посмотреть, как устроено создание форм под капотом.

Сейчас код формы такой:

class OrderForm(forms.Form):
    ship = forms.ModelChoiceField(queryset=Spaceship.objects, label='На чем летим', widget=RadioSelect)

Посмотрим на класс forms.Form:

class Form(BaseForm, metaclass=DeclarativeFieldsMetaclass):
    "A collection of Fields, plus their associated data."

Собственно здесь всё, больше кода (кроме нескольких комментариев после докстринга) нет.
Поэтому идём в родительский класс BaseForm, а также в метакласс DeclarativeFieldsMetaclass.

Как джанго отделяет среди атрибутов класса формы поля от других атрибутов и как у объекта формы появляется атрибут fields?
Чтобы было более понятно, о чем речь, добавлю еще один атрибут в класс нашей формы, атрибут field_order, это список полей, указывающий, в каком порядке их рендерить.

class OrderForm(forms.Form):
    ship = forms.ModelChoiceField(queryset=Spaceship.objects, label='На чем летим', widget=RadioSelect) 
    field_order = ['ship',]  

Вспоминаем основы ООП:

  1. Всё в Python — объекты.
  2. Классы сами по себе — объекты.

Привыкаешь всегда смотреть на классы только в формате класс(), т.е. когда объект класса вызывается и порождает другой объект — экземпляр класса.

Но давайте не будем создавать пока экземпляр класса нашей формы. А посмотрим, как создается сам класс формы.
За создание любого объекта в Python, в том числе класса, отвечает метод __new__. Чтобы переопределить поведение __new__ именно для классов-как-объектов, используют метаклассы. Собственно, это мы и видели в сигнатуре класса forms.Form — на второй позиции указан метакласс: metaclass=DeclarativeFieldsMetaclass.

Из описания метода __new__ этого метакласса мы и поймем, что делает джанго с атрибутами класса формы при создании этого класса (повторюсь — самого класса, не его экземпляра).

  1. cильно погружаться в этот исходный код не нужно, важные штуки я выделил комментариями (мои на русском, на английском — это комменты разработчиков джанго)
    def __new__(mcs, name, bases, attrs):
        # Collect fields from current class.
        current_fields = []
        for key, value in list(attrs.items()): # запускается цикл по всем парам "ключ-значение" атрибутов, которыми наделен класс
                                               # в нашем случае атрибута два: `ship` и `order_field`.  
            if isinstance(value, Field): # вот момент истины: оценивается, относится значение в атрибуте к класcу `Field`, классу полей джанго-форм
                current_fields.append((key, value)) # если относится, то атрибут пара "ключ-значение" заносится в список `current_fields`  
                attrs.pop(key) # а сам атрибут поля исключается (словарный метод `pop`) из числа атрибутов класса, т.е. теперь `OrderForm.ship` НЕ сработает  
        attrs['declared_fields'] = dict(current_fields) # зато у `OrderForm` появляется новый атрибут `declared_fields` и в нем как раз доступно поле `ship`.  

        new_class = super().__new__(mcs, name, bases, attrs)

        # Walk through the MRO.
        declared_fields = {}
        for base in reversed(new_class.__mro__):
            # Collect fields from base class.
            if hasattr(base, 'declared_fields'):
                declared_fields.update(base.declared_fields)

            # Field shadowing.
            for attr, value in base.__dict__.items():
                if value is None and attr in declared_fields:
                    declared_fields.pop(attr)
        # Итог создания класса нашей формы как самостоятельного объекта - два атрибута класса `base_fields` и `declared_fields`, в которых доступны 
        именно те атрибуты класса формы, которые являются полями.  
        new_class.base_fields = declared_fields
        new_class.declared_fields = declared_fields

Проверим. Возьмем класс нашей формы как отдельный объект (т.е. вызывать его, создавать другой объект — экземпляр класса, не будем).

order_form_class_as_obj = OrderForm

# к этому моменту `__new__` уже отработал, а значит, `OrderForm.ship`, должен вызвать ошибку.
order_form_class_as_obj.ship
...AttributeError: type object 'OrderForm' has no attribute 'ship' # действительно, атрибут `ship` исчез...

#...но должны появиться `declared_fields` и `base_fields` и там `ship` будет 
order_form_class_as_obj.base_fields # {'ship': <django.forms.models.ModelChoiceField object at 0x000001B27B3FD1F0>}
order_form_class_as_obj.declared_fields # {'ship': <django.forms.models.ModelChoiceField object at 0x000001B27B3FD1F0>}  
# всё работает, как и должно. Появились новые атрибуты-словари, и наше поле там. Ключ: название поля, значение: объект поля.  

# а вот атрибут `field_order`, раз не относится к классу `Field` (и его наследникам), должен быть по-прежнему доступен.  
order_form_class_as_obj.field_order # всё работает, возвращается список [<django.forms.models.ModelChoiceField object at 0x000001DE9F4BF2B0>]  

Продолжение выложу здесь в понедельник, 29 ноября, а в среду, 1 декабря в 19.00 по мск продолжим обсуждать джанго-формы на вебинаре.

Что почитать, освежить (но ни в коем случае не застревать, если что-то будет непонятно)

  • html-тег form
  • Атрибуты html-тега input
  • Как джанго ищет шаблоны
  • Как работает шаблонный тег url
  • Как джанго сопоставляет маршруты с контроллерами
  • Атрибут label поля джанго-формы
  • Виджет RadioSelect поля джанго-формы
  • Как устроены метаклассы в Python (русский перевод изумительной статьи с RealPython)

Работаем с джанго-формами. Часть 2

4.2 Дефолтный рендеринг формы не устраивает. Нужно более гибкое управление отображением

4.2.1. По каким правилам рендерится форма целиком и что можно изменить

Сейчас на странице наша форма выглядит так
image

А в шаблоне так

<form actions="" method="POST">
  {% csrf_token %}
  {{ space_form }}
</form>

В шаблонной переменной space_form находится экземпляр нашей формы OrderForm (мы передали его в словаре context через контроллер).

Когда объект формы целиком размещается в верстке (как в нашем случае), у объекта формы срабатывает метод __str__(отвечает за строковое представление объекта), который, в свою очередь,
вызывает метод формы as_table.

Вот как это выглядит под капотом:

#django.forms.forms.BaseForm
class BaseForm:
    ...
    def __str__(self):
        return self.as_table()

    def as_table(self):
        "Return this form rendered as HTML <tr>s -- excluding the <table></table>."
        return self._html_output(
            normal_row='<tr%(html_class_attr)s><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>',
            error_row='<tr><td colspan="2">%s</td></tr>',
            row_ender='</td></tr>',
            help_text_html='<br><span class="helptext">%s</span>',
            errors_on_separate_row=False,
        )

Из описания метода as_table видно, что он вызывает метод _html_output, передавая ему в качестве аргументов html-разметку для отображения поля, сообщений об ошибках, вспомогательного текста для поля и т.д.
Собственно, вот так и происходит превращение шаблонной переменной с объектом формы в полноценную html-разметку.

as_table оборачивает каждое поле формы в строку таблицы с невидимыми границами. Благодаря этому достигается выравнивание формы и каждое поле располагается строго под предыдущим.

Важный для понимания момент: за отображение html-тегов <input> и <label> для конкретного поля отвечает виджет этого поля. А вот методы as_... самой формы уже оборачивают теги каждого отдельного поля (оборачивают=заключают внутрь некой оболочки, оболочкой выступают например теги <p></p>), в итоге получается матрешка из html-разметки.

Помимо as_table, который срабатывает по умолчанию, есть методы as_p и as_ul, которые отличаются тем, в какой html-тег оборачивается каждое поле.
Если указать {{ space_form.as_p }}, каждое поле формы будет обернутов в абзацный тег <p></p>. Если указать {{ space_form.as_ul }}, каждое поле формы будет обернутов в списочный тег <li></li>.

Визуально результаты каждого из методов рендеринга фактически не будут отличаться, разве что при as_ul рядом с лейблом поля появится маркер списка
image

Фактически рендерить всю форму целиком из переменной с ее объектом не очень практично — верстка, которая заложена под капотом, достаточно топорна и вряд ли пригодится дальше чернового варианта страницы.

Для более гибкого управления рендерингом формы в шаблоне можно обращаться к каждому полю по отдельности.

4.2.2. Как перейти к управлению отображением каждого поля в отдельности

Есть два варианта.

Вариант 1.
Запустить цикл по объекту формы. Объект формы итерабелен, об этом нам говорит наличие методов __iter__ и __getitem__ под капотом
(кстати, вопрос о том, что представляют из себя итераторы, итерабельные объекты в Python и как реализовать протокол итератора, частый вопрос на собеседованиях).

class BaseForm:
    ...
    def __iter__(self):
        for name in self.fields:
            yield self[name]

    def __getitem__(self, name):
        """Return a BoundField with the given name."""
        try:
            field = self.fields[name]
        ...

При запуске цикла на каждой итерации будет отдаваться конкретное поле (в том порядке, в котором они перечислены в классе формы либо в атрибуте формы field_order).
Выглядеть это будет так:

<form actions="" method="POST">
  {% csrf_token %}
  <!-- запускаем цикл через специальные шаблонные теги -->  
  {% for field in space_form %}
    {{ field }} <!-- теперь у нас новая переменная в шаблоне, в которой "сидит" конкретное поле и через точку можно обращаться к различным его атрибутам -->
  {% endfor %}
</form>

Запуск цикла по полям формы особенно удобен, когда каждое поле мы оборачиваем в одну и ту же верстку.
Тогда вместо ее дублирования для каждого поля, можно доверить это циклу.

<form actions="" method="POST">
  {% csrf_token %}
  {% for field in space_form %}
  <div class=...> <!-- каждое поле будет обернуто html-тег div одного и того же класса, в классе описываем нужные css-стили -->
    {{ field }}
  </div>
  {% endfor %}
</form>

Важный момент: если вдруг страница отобразилась не в том виде, в каком вы ожидали, проверьте расположение между собой html-тегов и шаблонных тегов, управляющих разметкой.
Например, не выпал ли закрывающий html-тег из цикла (оказался под, а не над {% endfor %}). Или, наоборот, в цикл попали лишние html-теги, которые вы и не собирались повторять.

Вариант 2.
Взять напрямую интересующее поле, указав через точку его имя (имя атрибута в классе вашей формы). Очень частое выражение в Python, да и других языках, точечная нотация (dot notation). Ничего сверхъестственного это за собой не несет, это доступ к атрибуту объекта с использованием точки.

В нашем случае до поля выбора кораблей мы доберемся так {{ space_form.ship }}.

Перед тем, как продолжить работу с полем, нужно остановиться для прояснения принципиально важного момента — что такое класс BoundField.

4.2.3 Field и BoundField

Когда мы объявлем поле формы, например, так

ship = forms.ModelChoiceField(queryset=Spaceship.objects, label='На чем летим', widget=RadioSelect)

мы создаем объект конкретного поля, который, в конечном итоге, через цепочку наследования, всегда является объектом класса Field
(forms.ModelChoiceField наследник forms.Field, forms.CharField наследник forms.Field и т.д.).

Независимо от непосредственного родителя, у полей всегда есть атрибуты из конструктора базового класса Field.

Заглянем под капот джанго:

class Field:
    ...
    def __init__(self, *, required=True, widget=None, label=None, initial=None,
                 help_text='', error_messages=None, show_hidden_initial=False,
                 validators=(), localize=False, disabled=False, label_suffix=None)

У поля, например, будет атрибут .required, от значения которого зависит, пропустит ли is_valid отсутствие данных для поля или нет.

Есть атрибут label, о нем мы уже говорили выше, есть initial, куда можно передать начальное значение (value) поля и т.д.

Чтобы в python-коде (например, в forms.py или в коде контроллера), добраться до поля, нужно обратиться к атрибуту fields формы. fields — это словарь, поэтому далее используем квадратные скобки, внутри ключ — название поля. Так мы добираемся к объекту поля.
Например, если в переменной space_form находится экземпляр формы класса OrderForm, то к объекту поля ship мы доберемся так
space_form.fields['ship']. И далее через точечную нотацию мы уже можем работать с различными атрибутами поля.

Промежуточный итог:

  • все поля формы получают атрибуты класса Field и его наследников (классов, отвечающих за поля конкретного типа)
  • все поля формы помещаются в словарь в атрибуте fields формы, доступ к ним такой `объект_формы.fields[‘название_поля_формы’]

К полю формы в python-коде можно добраться ещё одним способом: объект_формы['название_поля']. Но — внимание — так мы получим не поле непосредственно, а объект класса BoundField.

На заметку. Когда мы любой python-объект (совсем не обязательно словарь) пишем в формате объект['какая_то_строка'], т.е. применяем квадратные скобки (square brackets notation), то вызывается метод __getitem__, определенный в классе этого объекта. Именно он отвечает за то, что будет происходить дальше. Если метод внутри класса не определен, то поднимется исключение TypeError: 'название_класса' object is not subscriptable.
Иными словами, если вы вдруг получаете ошибку is not subscriptable, значит, вы не к тому объекту приставили квадратные скобки.
Объекты джанго-форм subscriptable, к ним можно применить квадратные скобки. При указании в качестве ключа названия поля, под капотом сработает field.get_bound_field(self, name).
Т.е. вернется объект класса BoundField.

BoundField — это класс обертка над объектом нашего поля, т.е. объектом класса Field.

Поскольку BoundField — это обертка, то через нее, с помощью атрибута field можно добраться до объекта нашего поля.

Т.е. space_form.fields['ship'] и space_form['ship'].field приведут к одному и тому же — к объекту ModelChoiceField, наследнику Field.

У BoundField есть свои собственные атрибуты, которые позволяют не пробираться к field, а сразу вытащить какие-то из его атрибутов.

Например, у BoundField есть атрибут help_text. Такой же атрибут есть и у Field, в нем мы можем привести какой-то поясняющий текст для поля формы и отобразить его рядом с полем.

Соответственно, обращение к space_form.fields['ship'].help_text и space_form['ship'].field.help_text дадут один и тот же результат.
Однако у BoundField есть далеко не все атрибуты Field.

Например, чтобы проверить, обязательно поле или нет, нельзя использовать space_form.fields['ship'].required, потому что атрибута required у BoundField нет.

И теперь самое главное 😄: почему это всё так важно? Потому что в шаблоне страницы при цикле по полям формы или при доступе к полю напрямую используется как раз BoundField.

Поэтому, в {{ space_form.ship.какой_то_атрибут }} в качестве «какого_то_атрибута» можно выбрать только то, что перечислено в атрибутах BoundField,
потому что {{ space_form.ship }} в шаблоне — это то же самое, что space_form['ship'] в python-коде.

Если же через шаблонную переменную с полем нужно добраться до атрибутов из класса Field, которых нет в BoundField, того же required, то нужно использовать переходник в виде атрибута field, т.е. будет так {{ объект_формы.название_поля_формы.field.атрибут }}.

Попробуйте в шаблон страницы вставить {{ space_form.ship.field.required }}.

<body>
  <div class='container'>
    <h2>Заказ полета</h2>
    {{ space_form.ship.field.required }} <!-- добрались до атрибута required класса Field через атрибут field класса BoundField -->
  </div>
</body>

Результат:
image

На странице мы увидели значение атрибута requiredTrue. Поле обязательно.

Вот один из многих вариантов того, как это может пригодится на практике — по-разному стилизовать обязательные и не обязательные поля при рендеринге формы.

Отмечу, что if можно было бы вставить непосредственно в атрибут class, но для большей иллюстративности я сделал два разных div.

<form actions="" method="POST">
  {% csrf_token %}
  {% for field in some_form %} <!-- цикл по любой джанго-форме -->
     {% if field.field.required %}
      <div class='класс_с_особым_стилем_для_ОБЯЗАТЕЛЬНЫХ_полей'>
        {{ field }}
      </div>
     {% else %}
      <div class='класс_с_особым_стилем_для_НЕобязательных_полей'>
        {{ field }}
      </div>
     {% endif %}
  {% endfor %}
</form>

4.2.4. Рендерим поле ship отдельно

Обратимся в шаблоне к полю напрямую.

  <form actions="" method="POST">
    {% csrf_token %}
    {{ space_form.ship }}
  </form>

image

Что поменялось? В верстке исчезла обертка в виде табличных тегов (которые раньше давал form.as_table()), но это незаметно.
Зато видно, что исчез лейбл поля, нет На чем летим.

И здесь нужно запомнить важное правило: при непосредственном управлении полем в разметке нужно учитывать, что оно не монолитно.
Оно состоит из целого ряда элементов: само поле (например, поле для ввода текста), лейбл поля, вспомогательный текст (help text), текст ошибки, которые вернет бэкенд после проверки поля и т.д.
Всё это нужно самостоятельно указывать в шаблоне, используя атрибуты BoundField`.

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

  <form actions="" method="POST">
    {% csrf_token %}
    {{ space_form.ship.label }} <!-- label, один из атрибутов BoundField -->
    {{ space_form.ship }}
  </form>

Результат
image

Лэйбл вернулся.

4.2.5 Особенности полей с выбором одного или нескольких предложенных значений

Почему никуда не исчезали названия радиокнопок? Это особенность виджета RadioSelect и других виджетов, предполагающих выбор из заранее отрендеренных значений (чекбоксы, селекты).

За рендеринг каждой отдельной радиокнопки отвечает «подвиджет» (subwidget) и в качестве лейблов они используют названия объектов из переданного при создании поля набора записей.

Иными словами, через BoundField.label мы управляем лейблом всего набора радиокнопок (label всего поля ship), а не названиями каждой радиокнопки в отдельности.

Можно ли управлять отдельными виджетами (собственно говоря, каждым конкретным инпутом-радиокнопкой)? Да, можно.

Дело в том, что объект класса BoundField (а именно с ними мы работаем в шаблоне), итерабельны, т.е. по ним можно пройтись циклом.
Но что именно будет перебирать цикл? Смотри на реализацию метода __iter__ у BoundField

    def __iter__(self):
        return iter(self.subwidgets)

Перебираться будут как раз сабвиджеты, поэтому запускать цикл есть смысл только тогда, когда поле использует мультивиджет (радиокнопки, чекбоксы и т.п.).

Каждый сабвиджет (в нашем случае каждая радиокнопка) относится к классу BoundWidget и содержит, в частности, такие атрибуты и методы:

  • tag — сама кнопка (чек-бокс и т.п.), без подписи
  • choice_label — подпись к кнопке (чек-боксу и т.п.)
  • id_for_label — айдишник радиокнопки (в частности, нужен, чтобы связать надпись с конкретной кнопкой)

4.2.6 Берем управление отображением поля выбора кораблей полностью в свои руки

Теперь мы можем полностью избавиться от дефолтной обертки радиокнопок тегами li (а значит, назойливыми черными буллитами списка), и обернуть кнопки и подписи к ним во что захотим.

Попробуем такой пример

<form actions="" method="POST">
  {% csrf_token %}
  <!-- название всего поля (всей группы радиокнопок)-->
  {{ space_form.ship.label }}
  <!-- запускаем цикл по полю == перебираем все радиокнопки -->
  {% for radiobutton in space_form.ship %}
    {{ radiobutton }}
  {% endfor %}
</form>

Смотрим, что получилось
image

Исчезли черные кружки возле каждой радиокнопки, а сами кнопки расположились не в столбик, а в ряд. О чем это говорит?

О том, что дефолтная обертка радиокнопок в теги html-списка исчезла. Мы взяли вопрос рендеринга каждой кнопки под личный контроль и
джанго отдаёт только разметку для <input> и для <label>.

Вот как сейчас выглядит разметка группы радиокнопок — просто подряд идущие лейблы и инпуты, никаких оберток

<!-- название всего поля (всей группы радиокнопок)-->
На чем летим
<!-- запускаем цикл по полю == перебираем все радиокнопки -->
<label for="id_ship_0">
  <input type="radio" name="ship" value="1" id="id_ship_0" required>
   Crew Dragon
</label>
<label for="id_ship_1">
  <input type="radio" name="ship" value="2" id="id_ship_1" required>
  New Shepard
 </label>
<label for="id_ship_2">
  <input type="radio" name="ship" value="3" id="id_ship_2" required>
   VSS Unity
</label>

Сравните эту разметку, что была при рендеринге поля ship целиком.

Если интересно, почему кнопки расположились в ряд, почитайте о делении html-элементов на строчные и блочные.

Как уже отмечал, можно пойти ещё дальше и управлять отдельно отображением самой кнопки и подписью к ней.

Давайте попробуем этот инструмент: оформим подпись к каждой кнопке текстом красного цвета.

<!-- запускаем цикл по полю == перебираем все радиокнопки -->
{% for radiobutton in space_form.ship %}
  <!-- рендерим саму кнопку -->
  {{ radiobutton.tag }}
  <!-- рендерим подпись, переопределив тег label, чтобы добавить новый стиль -->
  <label for="{{ radiobutton.id_for_label }}" style="color: red;">
    {{ radiobutton.choice_label }}
  </label>
{% endfor %}

Что мы сделали:

  • запустили цикл по радиокнопкам (цикл по subwidgets)
  • сначала отобразили в разметке саму кнопку
  • потом дописали собственный тег label, в который добавили css-свойство color со значением red (делает текст красным)
  • в label мы также добавили айдишник радиокнопки, чтобы связать подпись и кнопку
  • отобразили подпись.

Результат
image

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

Продолжение выложу здесь в пятницу, 3 декабря, а в среду, 1 декабря в 19.00 по мск продолжим обсуждать джанго-формы на вебинаре.


Что почитать (освежить в памяти)

  • Протокол итерации в Python
  • Атрибуты объектов класса BoundField
  • Шаблонный тег for
  • Шаблонный тег if
  • Цикл по полям джанго-формы, полезные атрибуты
  • От чего защищают csrf-токены
  • Деление html-элементов на строчные и блочные
  • html-тег input type=»radio»
  • html-тег label

Работаем с джанго-формами. Часть 3

4.3. Прикручиваем картинки к радиокнопкам

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

4.3.1. Посмотрим детально, как работает ModelChoiceField

Что сейчас из себя представляет поле spac_ship в нашей джанго-форме?

Это поле класса ModelChoiceField. Логика этого поля такова:

  • взять набор записей из базы;
  • у каждой записи взять уникальный идентификатор (по умолчаню это первичный ключ (id, pk));
  • отобразить в html поле, предполагающее выбор из нескольких значений — радиокнопки, чекбоксы, выпадающий список;
  • каждому составному элементу html-поля (если, например, поле в виде радиокнопок, то каждой радиокнопке) присваивается атрибут value, значением
    которого является тот самый уникальный идентификатор записи.

Пример: набор записей в БД состоит из 3 записей с id 1, 2, 3 соответственно.
Если этот набор передать в ModelChoiceField с виджетом RadioSelect, то на странице появится три input type="radio" с value 1, 2 и 3 соответственно.

Если пользователь выберет радиокнопку, за которой стоит value=1, значит, на бэкенде мы будем обращаться к соответствующей таблице в БД к записи с id 1.

Ещё больше усилим пример :)

Заглянем в БД, в таблицу Spaceship. Чтобы открыть базу sqlite, я воспользуюсь очень удобным (да-да, звучит, как в рекламе) браузером DB Browser for SQLite.
Если ещё не установили, сделайте это, куда удобнее смотреть базу через браузер, чем через консоль. Вот ссылка — https://sqlitebrowser.org/dl/.

image

У нас три записи: id 1 — корабль Crew Dragon, id 2 — корабль New Shepard, id 3 — корабль VSS Unity.

Теперь посмотрим, как мы создавали поле ship в джанго-форме:

    ship = forms.ModelChoiceField(
        queryset=Spaceship.objects,
        label='На чем летим',
        widget=RadioSelect
    )

В параметр queryset мы передали Spaceship.objects, что равнозначно Spaceship.objects.all().

Пруфы, почему равнозначно? Вот кусочек кода из-под капота поля ModelChoiceField: self._queryset = None if queryset is None else queryset.all()

Итак, в параметре queryset мы передали все записи (а всего их 3) из модели Spaceship.

Это означает, что наше поле джанго-формы настрогает ровно 3 сабвиджета <input type="radio">.

Поскольку никакого особенного порядка сортировки мы в модели не задавали, то записи в наборе будут в порядке возрастания айдишников, значит и радиокнопки отрендерятся в том же порядке: сначала радиокнопка с value=1, потом с value=2 и, наконец, value=3.

Разумеется, мы можем взять в качестве queryset не все записи для модели, а какую-то часть.
Возьмем кверисет из одной записи Spaceship.objects.filter(id=1) (помним, что метод filter в джанго ORM возвращает именно кверисет, даже если внутри одна запись).

  ship = forms.ModelChoiceField(
      queryset=Spaceship.objects.filter(id=1),
      label='На чем летим',
      widget=RadioSelect
  )

Результат предсказуем: в верстке появится только одна радиокнопка, т.к. кверисет всего из одной записи

image

4.3.2. Откуда и в каком виде брать картинки кораблей

В модели Spaceship предусмотрено поле image:

class Spaceship(models.Model):
    ...
    image = models.ImageField(upload_to=get_upload_path,
                              verbose_name='изображение')

Кстати, что за get_upload_path? Это собственная функция, которая формирует путь к сохраняемой картинке.
Благодаря этой функции картинки не валятся скопом в папку media, а для каждой картинки внутри media автоматом создаётся своя подпапка

Физически загруженные картинки хранятся в директории, которую мы установили в settings.py по ключу MEDIA_ROOT. В нашем случае это
MEDIA_ROOT = BASE_DIR / 'media' (о том, что скрывается за BASE_DIR, я очень подробно писал в первой части пособия).

image

В таблице Spaceship в базе данных в свою очередь хранятся адреса привязанных к записям картинок.
image

Для того, чтобы отобразить картинку в html-странице, нам как раз нужен ее адрес. Его мы укажем в атрибуте src тега img.

Добраться до адреса картинки в базе можно так: объект_записи.название_поля_для_картинок.url.

Если, к примеру, в переменной spaceship_obj будет запись из таблицы Spaceship, то к адресу картинки, привязанной к этой записи,
мы доберемся так: spaceship_obj.image.url.

4.3.3. В чем проблема

Итак, мы поняли как добраться к адресу картинки для каждой записи. Для этого нужна… да, сама запись.

Заглянем в шаблон, еще раз посмотрим, как на странице появляются радиокнопки:

{% for radiobutton in space_form.ship %}
  <!-- рендерим саму кнопку -->
  {{ radiobutton.tag }}
  <!-- рендерим подпись, переопределив тег label, чтобы добавить новый -->
  <label for="{{ radiobutton.id_for_label }}">
    {{ radiobutton.choice_label }}
  </label>
{% endfor %}

В качестве итерируемого объекта выступает набор сабвиджетов, очень упрощая — просто кусочков html-разметки <input type="radio"...>

Перейти от сабвиджета к объекту записи из набора, который передавался при создании ModelChoiceField, нельзя.

Иными словами, никакого волшебного radiobutton.obj.image.url у нас нет.

4.3.4. Решаем проблему: создаём zip-итератор в контроллере

Если сфокусироваться на текущем коде шаблона страницы, то становится понятным, что мы:
а) должны оставить имеющийся цикл, на каждой итерации которого появляется кнопка и подпись к ней
б) должны дополнить цикл еще одной переменной, за которой будет стоять объект записи из кверисета, переданного в ModelChoiceField
в) адрес картинки этой записи мы будем на каждой итерации включать в тег img и показывать картинку рядом с кнопкой

Чтобы на каждой итерации у нас было две переменных, нам нужны два итерируемых объекта.

Один есть: это набор сабвиджетов. Тогда вторым будет… да, набор записей из модели. Тех самых, что передавались в ModelChoiceField.
Причем нам не нужны записи целиком, достаточно адресов картинок из них.

Сделать такой вот составной итерируемый объект нам поможет стандартный питоновский итератор zip.

Мы его создадим в контроллере и через контекст передадим в шаблон и тогда уже доработаем цикл.

Идём в контроллер (см. комментарии к новому коду в сниппете)

def flight_details(request):
    form = OrderForm()
    # собрали адреса всех картинок из кверисета
    ship_images = [ship.image.url for ship in form.fields['ship'].queryset]
    # создали zip-итератор
    ship_field = zip(form['ship'], ship_images)
    return render(
        request,
        template_name='ship.html',
        context={
            'space_form': form,
            # передали итератор в контекст шаблона в переменной ship_field
            'ship_field': ship_field
        }
    )

Что мы сделали:

  1. Взяли набор записей, для этого мы обратились к полю ship через form.fields['ship'] и дальше взяли значение атрибута queryset. Это тот самый queryset, который передавался полю в джанго-форме
  2. Тем самым мы гарантировали, что мы взяли именно тот набор записей, на основе которого рендерятся радиокнопки, и именно в том порядке, в котором они будут расположены
  3. С помощью list comprehension мы прошлись по набору, взяли из каждой записи адрес картинки и составили список из этих адресов
  4. Создали zip-итератор:
    • на первом месте поле (внимание — в данном случае мы взяли поле как объект класса BoundField, только он итерабелен)
    • за полем скрываются три радиокнопки (по числу записей в кверисете)
    • на втором месте список адресов картинок (и их, разумеется тоже три, т.к. они из того же набора записей)
    • поскольку источником обоих списков является один и тот же набор записей, мы уверены в том, что каждая пара «радиокнопка-картинка» будет правильной.
  5. Передали итератор в контекст шаблона (переменная ship_field).

4.3.5. Решаем проблему: модифицируем цикл создания радиокнопок в шаблоне

Теперь мы запустим цикл в шаблоне не по полю ship, а по нашему новому zip-итератору в переменной ship_field.

Благодаря этому у нас появятся адреса записей на каждой итерации и мы можем создать тег img для картинок.

<!-- теперь на каждой итерации у нас 2 переменных -->
{% for radiobutton, img_url in ship_field %}
  <!-- рендерим саму кнопку -->
  {{ radiobutton.tag }}
  <!-- рендерим подпись, переопределив тег label, чтобы добавить новый -->
  <label for="{{ radiobutton.id_for_label }}">
    {{ radiobutton.choice_label }}
    <!-- рендерим картинку, прикрепленную к записи из Spaceship -->
    <img src="{{ img_url }}" style="width: 200px; height: auto;">
  </label>
{% endfor %}

В теге img помимо адреса картинки (src), мы еще задали стилевые свойства, чтобы зафиксировать ширину каждой картинки, а высоту браузер подберет сам, чтобы сохранялись пропорции картинки.

Результат 🔥

image

4.4. Создаём поле выбора даты полета

К полю согласно ТЗ три требования:

  • оно должно называться «Когда летим»
  • выбор даты осуществляется с помощью календаря
  • должны быть доступны не раньше +1 месяц от текущей даты (тут мы сейчас немного упростим и заменим условие на +4 недели, так проще будет дельту времени задать)

В первой части пособия мы подробно рассматривали алгоритм подбора поля формы, которое будет получать данные для корреспондирующего поля модели.

В данном случае мы выбираем поле forms.DateField. Начальный код поля в джанго-форме будет выглядеть так:

flight_date = forms.DateField()

Даже не заглядывая в верстку, мы знаем, как это поле будет отображено

image

Дефолтным лейблом при этом будет Flight date.

4.4.1. Задаём подпись к полю

Поменять лэйбл просто, надо явно передать нужное значение полю в параметре label: flight_date = forms.DateField(label='Когда летим')

image

4.4.2. Меняем тип инпута

Разобраться с лейблом было легко, но есть куда более серьезная проблема. Виджет DateInput рендерит обычное текстовое поле ввода.
Пользователь должен напечатать дату! Помимо того, что это выглядит, мягко говоря, архаично, так ещё и формат ввода даты должен быть строго определенным.

Читаем документацию к полю DateField:

If no input_formats argument is provided, 
the default input formats are taken from DATE_INPUT_FORMATS if USE_L10N is False, 
or from the active locale format DATE_INPUT_FORMATS key if localization is enabled.

Никаких особенных форматов даты мы в настройках нашего проекта не устанавливали, но у нас установлена локализация в settings.py (строчка USE_L10N = True) поэтому на вход будут ожидаться следующие форматы:

DATE_INPUT_FORMATS = [
    '%d.%m.%Y',  # '25.10.2006'
    '%d.%m.%y',  # '25.10.06'
]

Это дефолтные форматы даты для русской локали.

Посмотрев, какие вообще могут быть типы у html-инпутов, мы увидели, что есть такой type="date", который как раз отображает календарик. Ровно то, что нам нужно.

type — это один из возможных атрибутов html-тега input.

Управлять тегами инпутов можно через словарь attrs виджета поля джанго-формы.

  1. Пробираемся к виджету. Для этого обращаемся к параметру widget поля и явно указываем в нем объект виджета:
flight_date = forms.DateField(
   label='Когда летим',
   widget=DateInput()
)
  1. Теперь в параметрах виджета нужно указать attrs и передать этому параметру словарь с нужными нам атрибутами (парами «ключ»-«значение», которые мы хотим видеть внутри <input>).
flight_date = forms.DateField(
   label='Когда летим',
   widget=DateInput(
      'attrs': {'type': 'date'}
   )
)

Вот. Теперь у нас будет рендерится <input type="date"...>. Проверим

image
image

Ура! Календарь готов.

4.4.3. Прикручиваем валидатор на бэкенде

Прежде чем перейти к решению задачи на конкретном поле, посмотрим на вопрос валидации в масштабе.

Самое главное: четко различать уровни валидации.

1. Валидация на фронте
Это валидаторы, которые включены в html-теги, либо джаваскрипт-код, который, опять же на строне браузера, может проверять вводимые пользователем данные.

Для каждого инпут-тега могут быть общие валидаторы (например, required) и специфичные, зависящие от типа (type) конкретного инпута.

Когда видим в верстке строку типа <input type="text" required minlength="10">, это означает, что есть поле для ввода пользователем текста, и у этого поля 2 валидатора:

  • во-первых, проверяется, что поле действительно заполнено (валидатор required)
  • во-вторых, проверяется, что длина введенного текста не менее 10 символов (валидатор minlength)

Какие валидаторы какому типу инпута можно прикрутить, нужно читать в спецификации к этому типу, например, в русскоязочной версии MDN.

Если данные пользователя не проходят проверку фронтовыми валидаторами, то сабмит формы (нажатие условной кнопки «Отправить») не приводит к ее отправке на бэк.

Вместо этого браузер сообщает пользователю, в каких полях он ошибся.

Суперважный момент: установка валидаторов на фронте никак не влияет на бэкенд. Иными словами, если по каким-то причинам фронт пропустил невалидные данные, то на бэкенде они будут с радостью приняты.

Другой разговор, что при использовании джанго-форм, может происходить так, что у поля появляется один и тот же (по логике работы) валидатор и на фронте, и на бэкенде.

Это связано с тем, что, как мы уже говорили, джанго-форма выступает сразу в двух ролях — и как инструмент рендеринга html-разметки (а значит, можно включить в нее и фронтовые валидаторы), и как инструмент проверки данных на бэкенде.

Пример: required. По дефолту, если поле джанго-формы создано на бэкенде с required=True, то и на фронте оно будет отрендерено с required в инпут теге.

Следовательно, даже если фронт пропустит пустое значение в этом поле, бэк подстрахует и вернет форму с ошибкой.

Но всё описанное, это не результат какой-то предопределенности (установил валидатор на фронте = автоматом продублировал на бэкенд), это запрограммированое поведение конкретных инструментов конкретного фреймворка.

Поэтому, если не уверены, что фреймворк за вас продублирует валидатор с фронта на бэкенд или наоборот, сделайте это сами.

2. Валидация в джанго-форме
Это валидация на бэкенде. Она независима от валидации на фронте и запускается при передаче в объект формы полученных в POST-запросе данных и вызове .is_valid() либо .errors (errors запустит is_valid).

Даже если не будет (или не сработает) валидация на фронте, то валидация через джанго-форму остановит плохие данные и пользователю можно вернуть ту же форму с указанием допущенных ошибок.

3. Валидация на уровне полей модели
Это тоже валидация на бэкенде, но пока мы ее затрагивать не будем. Но вернемся к ней, когда будем рассматривать класс ModelForm.

4.4.4. Валидатор минимальной даты

В поле джанго-формы можно установить и валидацию на бэкенде, и валидацию на фронтенде. Начнем с первой.

Чтобы установить валидатор на бэкенде, нужно указать его в параметре validators поля.

Важный момент. validators — это всегда список, даже если валидатор будет всего один.

flight_date = forms.DateField(
    label='Когда летим',
    # внимание: даже если валидатор один, он должен передаваться в списке
    validators=[],
    widget=DateInput(
        attrs={
            'type': 'date',
        }
    )
)

Нам нужен валидатор минимального значения даты (+4 недели от текущей). Для нам подойдет стандартный джанго-валидатор MinValueValidator.
Его особенность в том, что он может принимать не только какие-то простые значения, но и функции, возвращающие значение, которое принимается за минимальное.

Далее мы напишем маленькую функцию, которая и будет возвращать нужное нам значение. Воспользуемся стандартным модулем datetime.

def get_min_date():
    """Возвращает текущую дату, увеличенную на 4 недели."""
    return datetime.date.today() + datetime.timedelta(weeks=4)

Эту функцию (без вызова!) передадим в валидатор, а его в свою очередь поместим в список validators. Получится так:

flight_date = forms.DateField(
    label='Когда летим',
    validators=[MinValueValidator(get_min_date)],
    ...

Теперь в какой бы день пользователь не обратился к форме, она не пропустит дату, которая меньше чем дата обращения + 4 недели.

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

Но есть вариант еще более удобный для пользователя — сразу скрыть из календаря даты, которые он не может выбрать. За это отвечает валидатор на фронте.

4.4.5. Прикручиваем валидатор на фронте

Мы помним: чтобы сделать валидацию на фронте, нужно указать валидатор в html-разметке, в теге input. А ещё мы помним, что составом тегов внутри input мы можем управлять прямо из кода джанго-формы с помощью словаря attrs виджета поля.

Зная, что в input type="date" за валидацию минимальной даты отвечает атрибут min, передадим его в attrs

flight_date = forms.DateField(
    label='Когда летим',
    validators=[MinValueValidator(get_min_date)], # проверка минимальной даты на бэкенде
    widget=DateInput(
        attrs={
            'type': 'date',
            'min': get_min_date # проверка минимальной даты на фронтенде
        }
    )
)

Чтобы синхронизировать наши валидаторы, мы фронту тоже передадим функцию get_min_date. Вот что с ней произойдёт при рендеринге:

  • рендер под капотом джанго увидит, что в атрибуте min вызываемый (callable) объект
  • этот объект (наша функция) будет вызван
  • результат (к примеру, по состоянию на 3 декабря) — datetime.date(2021, 12, 31) (объект datetime)
  • в итоге будет возвращено строковое представление этого объекта (str(datetime.date(2021, 12, 31)), т.е. «2021-12-31»
  • в верстку пойдёт min="2021-12-31". Именно в таком (международном) формате YYYY-MM-DD и ожидает значение атрибут min тега input type="date".

Что почитать, освежить в памяти:

  • 9 уровней применения функции zip
  • list comprehensions за 5 минут
  • html-тег img
  • Поле модели ImageField
  • Свойство url полей модели для загрузки файлов
  • Поле джанго-формы DateField
  • Виджет DateInput
  • input type=»date»
  • form.errors
  • form.is_valid()
  • field.validators
  • MinValueValidator
  • datetime.date.today
  • datetime.timedelta
  • Почему str к объекту даты возвращает строку именно в формате ISO 8601

Полезные инструменты:

  • Страница установки DB Browser for SQlite

Работаем с джанго-формами. Часть 4

5. Создаём поле для выбора валюты платежа

Мы уже достаточно набили руку в создании полей джанго-формы, поэтому сразу в бой:

  1. Назовем поле currency.

  2. Класс поля джанго-формы — ChoiceField. Не ModelChoiceField, а именно ChoiceField, т.к. корреспондирующего поля в модели для данного поля формы нет.
    Иными словами, в модели нет такого поля, данными из которых мы бы нагенерировали опции выбора в форме (как мы это сделали для поля выбора корабля).

  3. Из описания поля ChoiceField в документации мы видим, что его стандартный виджет Select. А стандартный виджет Select, в свою очередь, рендерится в
    в виде выпадающего списка опций.

<select>
  <option ...>...
</select>

В рамках нашего ТЗ дефолтный виджет нас полностью устраивает, ничего переопределять не будем.

  1. Поле ChoiceField при создании принимает аргумент для параметра choices. В качестве аргумента передается список или кортеж с опциями, которые будет выбирать пользователь.

  2. Каждая опция представлена в виде кортежа из двух элементов. Первый — что будет приходить на бэкенд, второй — что будет видеть пользователь в форме,

Для нашей ситуации choices будет таким

(
   ('RUB', 'Российский рубль'),
   ('USD', 'Доллар США')
)

В выпадающем списке на странице в браузере пользователь будет видеть Российский рубль и Доллар США, а на бэкенд в составе POST-запроса будет приходить либо пара
"currency": "RUB", либо пара "currency": "USD".

  1. Согласно ТЗ в форме на странице поле должно называться «Валюта платежа», поэтому передадим соответствующую строку для параметра label поля.

В итоге код поля в джанго-форме будет таким

currency = forms.ChoiceField(
    choices=(
        ('RUB', 'Российский рубль'),
        ('USD', 'Доллар США')
    ),
    label='Валюта платежа'
)

Добавим его в шаблон html-страницы

 <div style="margin-top: 30px;">
   {{ space_form.currency.label }}
   {{ space_form.currency }}
 </div>

Отрендерится поля вот так:

image

Полный код формы теперь такой:

def get_min_date():
    """Возвращает текущую дату, увеличенную на 4 недели."""
    return datetime.date.today() + datetime.timedelta(weeks=4)


class OrderForm(forms.ModelForm):
    ship = forms.ModelChoiceField(
        label='На чем летим',
        queryset=Spaceship.objects,
        widget=RadioSelect,
    )
    flight_date = forms.DateField(
        label='Когда летим',
        validators=[MinValueValidator(get_min_date)],
        widget=DateInput(
            attrs={
                'type': 'date',
                'min': get_min_date
            }
        )
    )
    currency = forms.ChoiceField(
        label='Валюта платежа',
        choices = (
            ('RUB', 'Российский рубль'),
            ('USD', 'Доллар США')
        )
    )

Прежде чем двигаться дальше прочитайте каждую строчку кода и убедитесь, что вы на 100% понимаете эти строчки, например:

  • что такое ModelChoiceField?
  • для чего нужно явно указывать widget=RadioSelect?
  • а вообще, что такое виджет?
  • в чем отличие валидатора в строке validators=[MinValueValidator(get_min_date)], от валидатора в строке 'min': get_min_date
  • и т.д.

Если возникают трудности, лучше перечитать материал выше. Потому что цель учебы не в том, чтобы быстро проскочить по материалу. Это ничего не даст.

Цель — учиться писать код осмысленно, на 100% понимая, что вы хотите сказать или что хотел сказать тот, чей код вы читаете (а на практике читать чужой код придется куда чаще, чем писать собственный).

6. Рефакторим джанго-форму: используем класс ModelForm

6.1. Минимальный набор кода для создания модельной формы

До текущего момента мы создавали форму на основе джанго класса Form, наследника BaseForm.
У BaseForm есть еще один класс-наследник — класс ModelForm.

Он полезен, когда поля формы используются для получения данных, на основе которых будет формироваться запись для БД.

Иными словами, когда можно выстроить цепочку поле формы -> поле модели.

У нас как раз такой случай — 2 из 3 полей формы можно сопоставить с полями модели Order:

  • поле джанго-формы ship -> поле ship модели Order
  • поле джанго-формы flight_date -> поле flight_date модели Order.

Создание формы на базе класса ModelForm позволяет нам доверить создание полей формы самому джанго.

В минимальном варианте требуется следующее:

  • прописать внутри класса формы класс Meta
  • в классе Meta два атрибута:
    • model — модель, которую обслуживает джанго-форма
    • fields — список (или кортеж) полей модели (важно: именно модели, не формы), для которых джанго автоматически создаст поля в нашей форме.

6.2. Что стоит за «магией» создания модельной формы

Вот что представляет из себя модельная форма, если бы мы описали поля самостоятельно через «обычную» форму.

          Модельная форма                            "Обычная" форма
-------------------------------------------|----------------------------------------
class OrderForm(forms.ModelForm):          |class OrderForm(forms.Form):
                                           |    ship = forms.ModelChoiceField(label='Корабль', queryset=Spaceship.objects.all())
    class Meta:                            |    flight_date = forms.DateField(label='Дата полета')
        model = Order                      |
        fields = ['ship', 'flight_date']   |

Вот эту «магию» по превращению 'ship из метаопции fields в ship = forms.ModelChoiceField(label='Корабль', queryset=Order.objects.all()) джанго делает за нас.

Разберем, как он это делает:

  1. Джанго идёт в модель Order и смотрит, какой класс у поля ship этой модели. Видит, что класс ForeignKey
  2. Джанго смотрит «карту» соответствия классов полей модели классам полей формы. Видит, что классу поля модели ForeignKey соответствует класс поля формы ModelChoiceField.
  3. Поскольку поле ship модели Order через внешний ключ связано с моделью Spaceship, то атрибутом queryset для ModelChoiceField становится Spaceship.objects.all().
  4. Также джанго видит, что у поля ship есть verbose_name='корабль', т.е. человекочитаемое название, его он берет в качестве лейбла для поля формы.
  5. В качестве названия самого поля джанго берет то же название, что и поле модели, т.е. ship.

Так и рождается поле джанго-формы ship = forms.ModelChoiceField(label='Корабль', queryset=Spaceship.objects.all()).

С полем flight_date происходят точно такие же манипуляции.

6.3. Как быть с полем currency, его же нет в модели Order

Создание модельной формы (формы-наследника класса ModelForm) не исключает возможности объявлять поля формы самостоятельно, а не поручать это джанго.

Это делается за пределами внутреннего класса Meta ровно также, как мы это делали, собирая «обычную» джанго-форму.

class OrderForm(forms.ModelForm):
    currency = forms.ChoiceField(
        choices = (
            ('RUB', 'Российский рубль'),
            ('USD', 'Доллар США')
        ),
        label='Валюта платежа'
    )

    class Meta:
        model = Order
        fields = ['ship', 'flight_date']

По сути, мы сказали «Джанго, создай за нас поля формы ship и flight_date на основе одноименных полей модели Order, а ещё в форме будет поле currency, его создание мы полностью берем на себя».

Что произойдёт, если указать currency в fields внутри Meta? Тут возможны два сценария:

  1. Поле currency явно объявлено вне Meta (так, как сейчас). Тогда ничего не произойдёт, джанго проигнорирует наличие currency в fields.
  2. Поле currency не объявлено явно. Тогда джанго пойдёт в модель Order искать поле currency, не найдёт его там и вы увидите ошибку
django.core.exceptions.FieldError: Unknown field(s) (currency) specified for Order

Отсюда вывод: указывать в fields названия полей, которых нет в модели, как минимум, бессмысленно, а как максимум всё сломает.

6.4. Автоматически созданные поля не устраивают. Что делать?

Да-да, доверив создание полей ship и flight_date полностью джанго мы сталкиваемся с теми же проблемами, которые решали, когда объявляли поля самостоятельно:

  1. Не устраивает дефолтный виджет select для поля ModelChoiceField, нужны радиокнопки, а не выпадающий список опций.
  2. Поле для даты опять не календарик, а окошко для ввода даты текстом, плюс никаких валидаторов на фронте
  3. Дефолтные подписи к полям не подходят.

Иными словами, джанго создал

ship = forms.ModelChoiceField(label='Корабль', queryset=Spaceship.objects.all())

а нам-то нужно

ship = forms.ModelChoiceField(label='На чем летим', queryset=Spaceship.objects, widget=RadioSelect)

т.е. требуется переопределить label и widget.

Вариант 1
Для того, чтобы переопределить некоторые (но не все!) атрибуты полей в модельной форме, в Meta есть набор опций:

  • labels — для переопределения подписей к полям
  • help_texts — для указания поясняющего текста к полям, который потом можно отрендерить рядом с полем
  • widgets — для переопределения виджетов полей
  • field_classes — для переопределения класса поля формы (если не устраивает дефолтное сопоставление полей или поле кастомного класса)
  • error_messages — для переопределения сообщений об ошибках по их кодам

Каждый из этих атрибутов принимает словарь, в котором ключами выступают названия полей, а значениями — новые значения для label, для help_text или другого атрибута.

В нашем случае и для поля ship, и для поля flight_date нужно переопределить виджет и лейбл. Через Meta это будет выглядеть так:

    class Meta:
        model = Order
        fields = ['ship', 'flight_date',]
        widgets = {
            'ship': RadioSelect,
            'flight_date': DateInput(
                    attrs={'type': 'date', 'min': get_min_date}
                  )
            }
        labels = {
            'ship': 'На чем летим',
            'flight_date': 'Когда летим'
          }

Как видим, никакой магии — лейблы и виджеты, которые мы с вами указывали при объявлении полей самостоятельно, мы просто перенесли в соответствующие атрибуты внутри Meta.

Вариант 2
Поля ship и flight_date можно объявить явно, ровно так же как мы это делали в «обычной» форме.

class OrderForm(forms.ModelForm):
    ship = forms.ModelChoiceField(
        queryset=Spaceship.objects,
        label='На чем летим',
        widget=RadioSelect
    )
    flight_date = forms.DateField(
        label='Когда летим',
        widget=DateInput(
            attrs={'type': 'date', 'min': get_min_date}
        )
    )

    class Meta:
        model = Order
        fields = ['ship', 'flight_date', ]

Важный момент: чтобы переопределить класс поля, виджеты, вспомогательный текст, лейблы нужно использовать или вариант 1, или вариант 2.

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

Иными словами, если начали явно описывать поле вне Meta, то делайте это до конца.

Ещё важный момент: наверняка вы обратили внимание, что несмотря на то, что мы определили ship и flight_date явно, мы их оставили и в атрибуте fields класса Meta.

В чем смысл?

  1. Причина первая, банальная — без полей в fields мы вообще не можем создать модельную форму. Но зачем тогда использовать ModelForm, если можно создать «обычную» форму (наследника forms.Form)?
  2. Автоматическое создание полей формы — не единственная фишка ModelForm. Есть ещё как минимум две очень важных вещи:
  • при валидации модельной формы запускаются проверки не только на уровне формы, но и на уровне модели. Если мы создадим поле ship в обычной форме, то, разумеется, валидаторы, которые есть для одноименного поля в модели запускаться не будут (потому что связки «модель — форма» нет). В модельной же форме будут (если ship будет указано в fields внутри Meta).
  • в модельной форме есть методы save и save_m2m, возможности которых значительно упрощают создание записи в БД на основе данных из полей модельной формы.

Для поля формы currency всё остаётся так, как было написано выше, — поскольку корреспондирующего поля модели для него нет, то и в fields его указывать бессмысленно.

Какой вариант переопределения атрибутов полей модельной формы выбрать? Ответ прост — если вам нужно переопределить что-то, для чего предусмотрены опции в Meta (а именно виджет, вспомогательный текст, лейбл, класс поля, сообщения об ошибках), то воспользуйтесь вариантом 1. Если же опций в Meta не хватает (например, в Meta нет validators), тогда переопределяйте поля из fields явно, т.е. описывая их вне Meta.

Что почитать, освежить в памяти:

  • класс поля джанго-формы ChoiceField
  • виджет джанго-формы Select
  • как джанго подбирает класс поля формы для конкретного класса поля модели
  • как переопределить атрибуты поля модельной формы и его класс

Работаем с джанго-формами. Часть 5

7. Как устроена валидация в джанго-формах

Независимо от того, какую форму мы создаём — «обычную» (наследника forms.Form) или модельную (наследника forms.ModelForm) — валидация на уровне формы устроена одинаково. Фишка модельной формы в том, что после валидации на уровне формы она подключает валидацию на уровне модели.

7.1. Как запустить валидацию данных в джанго-форме

Чтобы джанго-форма начала процедуру валидации нужны две вещи:

  1. Данные, которые нужно валидировать. Они передаются в параметре data при создании объекта формы.
    В качестве данных для проверки мы берем данные, которые пришли с фронтенда в словаре request.POST.
order_form = OrderForm(data=request.POST)
  1. Нужно запустить валидацию. Для этого нужен экземпляр джанго-формы с переданными ему данными для проверки и вызов у него одного из двух методов (атрибутов):
  • .is_valid()
  • .errors

Т.е. order_form.is_valid() и order_form.errors (обратите внимание, errors без скобок, т.к. это проперти) будут иметь один и тот же результат — запуск валидации.

Теперь сделаем экскурс в исходный код Django. Круто, когда не доверяешься чьим-то текстам (например, моим), а знаешь наверняка, потому что заглядывал под капот.

Важный момент: все выкладки из исходного кода даны по последней (4.0) версии Django, но они абсолютно актуальны и для версии 3.2 и для версии 2.2 (к вопросу о том, что не надо переживать, что вот вышла 4-я джанга, а мы изучаем 2.2 или 3.2, радикальные изменения больших кусков фреймворка происходят очень редко).

Код метода is_valid()

def is_valid(self):
    """Return True if the form has no errors, or False otherwise."""
    return self.is_bound and not self.errors

Видим, что is_valid возвращает True, если нет ошибок (not self.errors) и если в форму вообще передавались какие-то данные в аргументе data (is_bound).

Распутываем клубок и идем смотреть как устроен self.errors

@property
def errors(self):
    """Return an ErrorDict for the data provided for the form."""
    if self._errors is None:
        self.full_clean()
    return self._errors

Если в атрибуте _errors ничего нет (а на старте валидации и не может быть в принципе), то запускается метод full_clean экземпляра нашей формы.

Теперь исходный код метода full_clean формы

def full_clean(self):
    """
    Clean all of self.data and populate self._errors and self.cleaned_data.
    """
    self._errors = ErrorDict()
    if not self.is_bound:  # Stop further processing.
        return
    self.cleaned_data = {}
    # If the form is permitted to be empty, and none of the form data has
    # changed from the initial data, short circuit any validation.
    if self.empty_permitted and not self.has_changed():
        return

    self._clean_fields()
    self._clean_form()
    self._post_clean()

В этом коде сердце валидации и мы можем понять ее фундамент:

  1. Создаются два словаря — словарь для сбора данных об ошибках (self._errors) и словарь для сбора проверенных, не вызвавших ошибок, данных (self.cleaned_data).
  2. Одна за другой следуют три волны проверок:
  • методом _clean_fields()
  • методом _clean_form()
  • методом _post_clean()

Видим, что метод full_clean формы ничего не возвращает. Его задача запустить методы различных проверок и через них наполнить (если есть чем) словари ошибок и проверенных данных.

7.2. Первая волна валидации — метод _clean_fields()

Если очень коротко, то суть метода _clean_fields в том, чтобы запустить цикл по всем полям формы.
На каждой итерации у конкретного поля вызывается метод clean, который, в свою очередь, запускает несколько проверок значения, которое поступило для этого поля.

7.2.1 Как работает метод clean поля

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

В request.POST пришел словарь {'ship': '1', 'flight_date': '2022-01-31', 'currency': 'RUB'}.

Для каждого ключа из этого словаря в джанго-форме есть одноименное поле.

Мы создаём экземпляр формы и помещаем туда данные order_form = OrderForm(data=request.POST). Сделав это, наша форма теперь считается «связанной данными» (is bound).

Запускаем валидацию order_form.is_valid().

Поскольку данные в форме есть, т.е. order_form.is_bound возвращает True, то запускается полноценная валидация.

Первым делом у формы срабатывает _clean_fields, это означает, что:

  • значение '1' передается полю формы ship (полю класса ModelChoiceField) и у этого поля вызывается метод clean, который проверяет значение 1
  • значение '2022-01-31' передается полю формы flight_date (полю класса DateField) и у этого поля вызывается метод clean, который проверяет значение 2022-01-31
  • значение 'RUB' передается полю формы currency (полю класса ChoiceField) и у этого поля вызывается метод clean, который проверяет значение 'RUB'.

К какому бы классу не относилось конкретное поле формы, все они в конечном счете наследники класса Field. Поэтому именно там мы посмотрим описание метода clean.

def clean(self, value):
    """
    Validate the given value and return its "cleaned" value as an
    appropriate Python object. Raise ValidationError for any errors.
    """
    value = self.to_python(value)
    self.validate(value)
    self.run_validators(value)
    return value

Код совершенно несложный:

  • сначала поступившее значение преобразуется методом to_python поля
  • затем проверяется методом validate поля
  • затем проверяется методом run_validators

Далее рассмотрим все три метода на примере поля flight_date и значения '2022-01-31'.

7.2.1.1 Метод to_python поля

Задача этого метода в каждом поле — нормализовать поступившую строку с данными, привести ее к какому-либо Python-объекту.
Каким-либо образом переопределять этот метод для полей «из коробки» (т.е. классов, которые предлагает джанго) вам не нужно.
Просто знайте, что такой метод есть и зачем он нужен.

В каждом классе полей джанго-формы логика to_python своя. Например, если поле класса IntegerField, то поступившие значение будет преобразовываться в целое число вызовом int(value).

У нас поле DateField и его логика to_python в том, чтобы поступившую строку 2022-01-31 преобразовать в объект datetime.date следующим образом

datetime.datetime.strptime(value, format).date()

В результате после to_python строка 2022-01-31 станет объектом datetime.date(2022, 1, 31).

7.2.1.2 Метод validate поля

Метода validateвполне может не быть в классе конкретного поля, тогда работает validate из класса-родителя Field

def validate(self, value):
    if value in self.empty_values and self.required:
        raise ValidationError(self.error_messages['required'], code='required')

Т.е. по сути задача validate проверить, что для обязательного для заполнения поля пришли какие-либо данные.

Так же, как и в случае с to_python, переопределять это поведение вам вряд ли понадобится.

7.2.1.3 Метод run_validators поля

Этот метод запускает валидаторы, которые мы передали через параметр validators. Вспомним, как объявляли поле flight_date формы.

    flight_date = forms.DateField(
        label='Когда летим',
        validators=[MinValueValidator(get_min_date)], # валидаторы отсюда запускает `run_validators`  
        widget=...

Сам метод run_validators трогать не нужно, просто следует знать, что валидаторы можно передать списком через validators.

Теперь мы можем описать весь путь строки '2022-01-31' при обработке методом clean поля:

  1. to_python превращает в datetime.date(2022, 1, 31)
  2. validate пропускает дальше, т.к. для обязательного пришли данные
  3. run_validators запускает MinValueValidator(get_min_date), которые тоже пропускает объект даты, т.к. она не меньше минимальной

7.2.2. Что происходит после отработки метода clean поля?

Джанго ищет, а есть ли в классе нашей формы метод, название которого соответствовало бы формату def clean_<название_поля>. Вот как это описано в исходном коде

if hasattr(self, 'clean_%s' % name):
    value = getattr(self, 'clean_%s' % name)()
    self.cleaned_data[name] = value

Этот метод вы описываете самостоятельно и только тогда, когда проверок через to_python, validate и run_validators вам недостаточно.

В методе приводится нужная логика проверок и проверенное значение (в случае успеха) передается в словарь cleaned_data.

Остановимся и посмотрим, какая последовательность проверок у нас вырисовывается

is_valid() # старт валидации
    errors # второй вариант, как можно запустить валидацию
      full_clean()
        _clean_fields() # запуск цикла с перебором каждого поля формы
            # у каждого поля
            clean() # всегда
                to_python() # всегда
                validate() # всегда
                run_validators() # если передавали что-то в validators
            clean_<название_поля>() # если самостоятельно описали этот метод внутри класса формы

После вызова clean и (при наличии) clean_<название_поля_формы> работа _clean_fields заканчивается и в дело вступает следующий этап проверок — метод _clean_form() формы.

7.3. Как работает _clean_form и clean джанго-формы

После того, как провалидировано значение для каждого поля в отдельности, запускается метод _clean_form, позволяющий проверить все или часть полей совместно.

Посмотрим исходный код метода _clean_form:

def _clean_form(self):
    try:
        cleaned_data = self.clean()
    except ValidationError as e:
        self.add_error(None, e)
    else:
        if cleaned_data is not None:
            self.cleaned_data = cleaned_data

Логика метода:

  1. Запустить метод clean формы
  2. Если этот метод поднимет исключение ValidationError, то добавить это исключение в словарь с ошибками
  3. Если метод отработает без ошибок, то есть два варианта:
  • ничего не делать, если успешно отработавший clean вернул None
  • если clean что-то вернул, то это «что-то» становится новым словарем валидированных данных всей формы.

По поводу последнего нужно несколько пояснений. None может вернуться в трех случаях:

  • функция (метод) заканчивается return без значения;
  • функция (метод) заканчивается return None;
  • функция (метод) в принципе не содержат инструкцию return, т.е. не возвращают ничего.

Как правило, при описании логики метода clean формы ничего не возвращают. Т.е. либо метод поднимает исключение (==проверка провалена), либо метод не возвращает ничего (т.е. исключение не поднялось, значит, проверка прошла успешно, и можно использовать ранее сформированный словарь cleaned_data).

Метод clean мы описываем самостоятельно внутри формы, если хотим проверить уже отвалидированные значения для полей между собой или проверка требует участия значений из нескольких полей

У нас есть как раз такая задача: нам нужно проверить, что в выбранном пользователем корабле на выбранную дату есть места.

Т.е. нам нужно сделать проверку, в которой будут участвовать значения из двух полей — поля ship и поля flight_date.

Напишем код этой проверки (комментарии по ходу кода):

def clean(self):
    # берем значение поля `flight_date` из словаря валидированных данных
    flight_date = self.cleaned_data['flight_date']
    # берем значение поля `ship` из словаря валидированных данных
    ship = self.cleaned_data['ship']
    # делаем запрос к таблице заказов - считаем, сколько уже заказов есть на тот же корабль и на ту же дату
    existing_orders = Order.objects.filter(
        flight_date=flight_date,
        ship=ship
    ).count()
    # если количество заказов больше или равно вместимости выбранного корабля
    # capacity - это поле таблицы Spaceship, в котором хранится информация о предельном числе мест на конкретном корабле
    if existing_orders >= ship.capacity:
        # поднимаем исключение с описанием ошибки
        raise forms.ValidationError(
            'К сожалению, на эту дату мест нет. '
            'Пожалуйста, выберите другую дату или другой корабль.'
        )

Заметьте, что наш метод clean ничего не возвращает (return нет). Потому что задача метода не добавить или изменить что-то в существующем словаре cleaned_data, а подтвердить его правильность путем дополнительных проверок с участием значений из нескольких полей.

Дополним схему валидации новыми методами:

Остановимся и посмотрим, какая последовательность проверок у нас вырисовывается

is_valid() # старт валидации
    errors # второй вариант, как можно запустить валидацию
        full_clean()
            _clean_fields() # запуск цикла с перебором каждого поля формы
                # у каждого поля
                clean() # всегда
                    to_python() # всегда
                    validate() # всегда
                    run_validators() # если передавали что-то в validators
                clean_<название_поля>() # если самостоятельно описали этот метод внутри класса формы
           _сlean_form()
                _clean() # описываем самостоятельно внутри класса формы, если требуется проверка с участием значений из нескольких полей

Остался ещё один рубеж валидации в форме — метод _post_clean(). Он запускается только в модельных формах (формах-наследниках forms.ModelForm).

7.3.1. Как отрендерить на странице в браузере ошибки, которые вернет метод clean формы?

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

Они записываются в словарь «ошибок вне полей», он доступен через вызов метода non_field_errors() самого объекта формы.

Объект нашей формы находится в переменной space_form, поэтому ошибки от clean джанго-формы отрендерятся в том месте шаблона страницы, где мы пропишем {{ space_form.non_field_errors }}

Разместим данные об ошибках от clean в самом начале формы

    <form actions="" method="POST">
      {% csrf_token %}
      {{ space_form.non_field_errors }}
      ...

А теперь попробуем сделать заказ полета на CrewDragon в день, когда мест на корабле уже нет (число заказов == количество мест на корабле).

Страница с формой после проверки на бэкенде отрендерится так

image

7.4. Как работает _post_clean модельной формы

Задача метода _post_clean модельной формы — запустить валидацию на уровне модели, которую обслуживает джанго-форма (модель, указанная в model в Meta).

«Проверка на уровне модели» означает, что в полях модели и на уровне всей модели тоже могут быть различные проверочные механизмы (валидаторы, ограничения (constraints)) и вот _post_clean как раз и запускает эти механизмы (но есть исключения, о них тоже скажу).

Как _post_clean модельной формы запускает валидацию в модели? Очень просто. У любой модели есть метод full_clean (не путать с full_clean формы).

Обратимся к документации:

Этот метод вызывает Model.clean_fields(), Model.clean(), и Model.validate_unique()(если ``validate_unique() равно True) в указанном порядке и вызывает исключение ValidationError, которое содержит атрибут message_dict с ошибками всех трех этапов проверки.

Метод clean_fields модели действует ровно также как одноименный метод джанго-формы: берет значение для поля и прогоняет его через три проверки — to_python, validate и run_validators (см. исходный код).

Метод clean модели нужно описать самостоятельно, если требуются дополнительные проверки с участием значений из нескольких полей.

Вот что говорит документация:

Этот метод должен быть переопределен, если вам нужна дополнительная проверка модели или изменить значения атрибутов. Для объектов, вы можете определить его для автоматического определения полей, или для проверки, которая требует значения нескольких полей.

Метод validate_unique модели проверит все ограничения по уникальности для валидируемых полей (unique=True внутри поля, unique_together в Meta, UniqueConstraint в Meta. Для UniqueConstraint, правда, есть исключение, о нем ниже). Повторюсь: проверка будет касаться только полей, которые указаны в модельной форме.

Вернемся к коду нашей модельной формы и увидим, что для flight_date сейчас в форме нет валидатора, который мы прикручивали в «обычной» (до превращения в модельную) форме. Этот валидатор должен проверять, что выбранная дата не меньше чем на 4 недели позже текущей даты.

class OrderForm(forms.ModelForm):
    currency = forms.ChoiceField(
        choices = (
            ('RUB', 'Российский рубль'),
            ('USD', 'Доллар США')
        ),
        label='Валюта платежа'
    )

    class Meta:
        model = Order
        # поле `flight_date` модельное, вне `Meta` мы его не описывали, а внутри `Meta` валидаторы задать нельзя
        fields = ['ship', 'flight_date', 'currency']
        widgets = {
            'ship': RadioSelect, 
            'flight_date': DateInput(attrs={'type': 'date','min': get_min_date})
        }
        labels = {'ship': 'На чем летим', 'flight_date': 'Когда летим'}

У нас есть два варианта (причем они не исключают друг друга):

  1. Определить поле формы flight_date явно вне Meta и передать ему validators=[MinValueValidator(get_min_date)]
  2. Точно такой же валидатор прикрутить к полю flight_date в модели Order (модели, которую обслуживает наша форма).

Не будем менять код формы и задействуем второй вариант.

# spaceflights/models.py
...
def get_min_date():
    """Возвращает текущую дату, увеличенную на 4 недели."""
    return datetime.date.today() + datetime.timedelta(weeks=4)

class Order(models.Model):
    ...
    flight_date = models.DateField(
        # перенесли валидатор из формы в модель
        validators=[
            MinValueValidator(
                get_min_date,
                message=f"Дата должна быть не меньше {get_min_date().strftime('%d-%m-%Y')}"
            )
        ],
        verbose_name='дата полета',
    )
    ... 

Давайте разберемся, как будет происходить валидация выбранной пользователем даты полета через модельную форму:

  1. в словаре request.POST на бэкенд приходит строка с датой по ключу flight_date
  2. после передаче этого словаря через параметр data в форму и вызова .is_valid() джанго ищет среди полей формы поле с именем flight_date
  3. в поле формы flight_date (которое относится к классу DateField) строка с датой преобразуется в объект datetime.date
  4. после валидации остальных значений из request.POST джанго через метод clean() формы проверяет, есть ли на выбранную дату места на выбранном корабле
  5. если валидация методом clean формы прошла успешна, джанго идет в поле flight_date модели Order и запускает теперь уже проверки на его уровне
  6. в поле модели flight_date есть валидатор MinValueValidator(get_min_date), поступившее значение проходит проверку этим валидатором.

7.4.1. form.instance — особенность работы _post_clean

Во время работы _post_clean (который, как мы помним, актуален только для модельных форм) идёт постепенное создание инстанса (instance) объекта записи, который в последующем можно записывать в базу через form.save.

Для этого в классе BaseModelForm есть даже специальный метод construct_instance.

Вот как суть этого метода описана в исходном коде

Construct and return a model instance from the bound form‘s
cleaned_data, but do not save the returned instance to the database.

Выглядит это так:

  1. Допустим, форма обслуживает модель Order
  2. Сначала form.instance = Order() — т.е. пустой объект записи, никакие поля не заполнены
  3. После валидации значения для поля ship модели происходит form.instance.ship = <проверенное_значение_из_поля_ship_модельной_формы>
  4. После валидации значения для поля flight_date модели происходит form.instance.flight_date = <проверенное_значение_из_поля_flight_date_модельной_формы>

Повторюсь: form.instance — это подготовленный, но еще не сохраненный в базу объект записи. В этом объекте вполне может не хватать данных для какого-либо поля (потому что они, по самым разным причинам, не поступали через форму).

Работа с form.instance в контроллере («вьюхе») позволяет дополнить объект записи новыми данными, чтобы к моменту сохранения объекта записи в БД в нем были все необходимые данные.

Важный момент: в обычных (не модельных) формах атрибута instance нет.

7.4.2. Картина всей последовательности валидации с учетом _post_clean

is_valid() # старт валидации
    errors # второй вариант, как можно запустить валидацию
        full_clean()
            _clean_fields() # запуск цикла с перебором каждого поля формы
                # у каждого поля
                clean() # всегда
                    to_python() # всегда
                    validate() # всегда
                    run_validators() # если передавали что-то в validators
                clean_<название_поля>() # если самостоятельно описали этот метод внутри класса формы
           _сlean_form()
                _clean() # описываем самостоятельно внутри класса формы, если требуется проверка с участием значений из нескольких полей
 ===============================Дальше только для модельных форм========================================
           _post_clean()
                full_clean(validate_unique=False) # вызывается `full_clean` объекта модели (модели, НЕ формы)
                    clean_fields() # у каждого валидируемого поля модели вызывается метод `clean`  
                    clean()
                validate_unique() # вызывается проверка ограничителей по уникальности, установленных для объекта модели (при наличии таковых)

7.5. Вопросы и подводные камни, связанные с валидацией в форме

1. Что НЕ проверит валидация данных через модельную форму?

Валидация через модельную форму НЕ проверит соблюдение ограничений в модели (constraints), кроме ограничений уникальности.

Иными словами, если у вас в классе Meta модели объявлен атрибут constraints и в нем помимо (или вместо) UniqueConstraint есть CheckConstraint (например, вы запрещаете указывать одни и те же данные в двух разных полях), CheckConstraint при валидации модельной формы проверяться НЕ будет.

Обратимся к документации:

In general constraints are not checked during full_clean(), and do not raise ValidationErrors. Rather you’ll get a database integrity error on save(). UniqueConstraints without a condition (i.e. non-partial unique constraints) are different in this regard, in that they leverage the existing validate_unique() logic, and thus enable two-stage validation. In addition to IntegrityError on save(), ValidationError is also raised during model validation when the UniqueConstraint is violated.

Ещё раз: In general constraints are not checked during full_clean(), and do not raise ValidationErrors («По общему правилу ограничения НЕ проверяются при вызове full_clean() и не поднимают ValidationError«). Исключение — UniqueConstraint.

Но и UniqueConstraint будут проверены не все. Вне проверки останутся UniqueConstraint с условием. Пример такого ограничения есть в документации.

Если CheckConstraint будет нарушено (или UniqueConstraint с условием), то при попытке сохранить в базу валидированных данных, вы получите исключение IntegrityError.

Как быть? Есть два варианта:

  1. Предусмотреть обработку IntegrityError (через try - except) при вызове form.save
  2. Предусмотреть валидацию аналогичную CheckConstraint (или UniqueConstraintс условием) в джанго-форме, например, в методе clean.

2. is_valid() вернул True — значит, при вызове form.save в базу всё запишется без проблем?

Как говорится, it depends. Зависит от двух моментов:

  1. Достаточно ли данных, которые поступили и были проверены через джанго-форму, для создания записи в конкретной таблицы. Если не хватает данных для какого-либо поля, это поле обязательно и у него нет дефолтного значения, то конечно сохранение в базу окончится неудачей.
  2. Настроена обработка исключений, которые могут возникнуть из-за проверок, которые не охвачены валидацией (см. предыдущий вопрос).

3. Где лучше размещать валидаторы — в форме или в в модели, стоит ли их дублировать?

Универсального ответа нет.

Нужно определить (даже если форма модельная) — есть ли у поля формы корреспондирующее поле в модели. Например, в нашей OrderForm у поля currency нет корреспондирующего поля в модели.
В таком случае валидатор нужен в поле формы, больше ему отработать негде.

Если поле формы связано с полем модели, то нужно оценить, как вообще устроена последовательность проверок в конкретной форме.

В примере с OrderForm мы перенесли валидатор минимальной даты в поле модели. В чем может быть нелогичность этого шага?

Проверки на уровне модели начинаются строго после того, как отработали все проверки на уровне формы.

В нашей форме есть метод clean, который проверяет наличие мест на выбранном корабле на выбранную дату, а для этого дергает базу (отправляет запрос к ней).

Т.е. сначала мы дергаем базу в clean формы, а только потом, уже в модели, мы проверяем, а дата-то вообще ниже минимальной или нет.

Получается, мы можем напрасно дергать базу, если изначально дата по критерию минимальности не проходит. Логичнее сначала проверить минимальность даты (через validators в поле формы), а потом уже в clean (если всё хорошо) обращаться к базе для вычисления количества заказов на конкретный день.

Значит, нужно убрать валидатор из поля модели и перенести его в поле формы? Тут тоже надо подумать. Само по себе дублирование валидатора в поле модели и в поле формы ни хорошо, ни плохо.

Нужно решить, а как в вашем проекте данные будут попадать в базу. Только через форму по конкретному url или как-то ещё?

Если вариантов записи в базу несколько (например, не только через конкретную форму, но и через админку или через API), то, конечно, валидаторы в модели нужно оставлять.

Что почитать, освежить в памяти:

  • Проверка форм и полей форм
  • Валидаторы полей формы
  • Проверки в кастомном поле формы
  • Как написать проверку методом clean_названиеПоляФормы
  • Как работает метод clean формы
  • Метод non_field_errors формы
  • Метод full_clean модели
  • Установка ограничений в модели
  • Django’s Field Choices Don’t Constrain Your Data(маленькая, но очень познавательная статья)

Понравилась статья? Поделить с друзьями:
  • Руководство по эксплуатации маз 6317
  • Эбрантил уколы инструкция по применению цена
  • Apple watch руководство пользователя на русском
  • Ловелас форте инструкция по применению для мужчин отзывы противопоказания
  • Кальфотон для животных инструкция по применению для крс цена