Создание вашего первого приложения Django, часть 2
Это руководство продолжает материал, на котором остановилось Руководство 1. Мы настроим базу данных, создадим вашу первую модель и кратко познакомимся с автоматически создаваемым сайтом администрирования Django.
Где получить помощь:
Если при работе с этим руководством у вас возникли трудности, перейдите к разделу Получение помощи в FAQ.
Настройка базы данных
Теперь откройте mysite/settings.py. Это обычный модуль Python с переменными уровня модуля, представляющими настройки Django.
По умолчанию конфигурация DATABASES использует SQLite. Если вы новичок в работе с базами данных или просто хотите попробовать Django, это самый простой вариант. SQLite входит в состав Python, поэтому для работы с базой данных вам не потребуется устанавливать что-либо ещё. Однако, начиная свой первый настоящий проект, вы можете захотеть использовать более масштабируемую базу данных, например PostgreSQL, чтобы в будущем избежать сложностей при смене базы данных.
Если вы хотите использовать другую базу данных, ознакомьтесь с разделом подробнее о настройке и запуске базы данных.
Пока вы редактируете mysite/settings.py, задайте для TIME_ZONE свой часовой пояс.
Также обратите внимание на настройку INSTALLED_APPS в начале файла. В ней указаны имена всех приложений Django, активированных в данном экземпляре Django. Приложения можно использовать в нескольких проектах, а также упаковывать и распространять, чтобы другие могли использовать их в своих проектах.
По умолчанию в INSTALLED_APPS перечислены следующие приложения, входящие в состав Django:
-
django.contrib.admin– Сайт администрирования. Скоро вы им воспользуетесь. -
django.contrib.auth– Система аутентификации. -
django.contrib.contenttypes– Платформа для типов содержимого. -
django.contrib.sessions– Платформа для работы с сеансами. -
django.contrib.messages– Платформа для работы с сообщениями. -
django.contrib.staticfiles– Платформа для управления статическими файлами.
Эти приложения включены по умолчанию для удобства в наиболее распространённых случаях.
Однако некоторые из этих приложений используют как минимум одну таблицу базы данных, поэтому прежде чем их использовать, нам нужно создать таблицы в базе данных. Для этого выполните следующую команду:
$ python manage.py migrate
...\> py manage.py migrate
Команда migrate проверяет настройку INSTALLED_APPS и создаёт все необходимые таблицы базы данных в соответствии с настройками базы данных в файле mysite/settings.py и миграциями, поставляемыми вместе с приложением (мы рассмотрим их позже). Для каждой применённой миграции будет выведено сообщение. Если вам интересно, запустите клиент командной строки для своей базы данных и введите \dt (PostgreSQL), SHOW TABLES; (MariaDB, MySQL), .tables (SQLite) или SELECT TABLE_NAME FROM USER_TABLES; (Oracle), чтобы вывести таблицы, созданные Django.
Для минималистов
Как мы уже говорили, приложения по умолчанию включены для наиболее распространённых случаев, но они нужны не всем. Если вам не нужны некоторые или все из них, можете закомментировать или удалить соответствующие строки из INSTALLED_APPS перед запуском migrate. Команда migrate будет запускать миграции только для приложений, перечисленных в INSTALLED_APPS.
Создание моделей
Теперь мы определим модели — по сути, структуру вашей базы данных с дополнительными метаданными.
Философия
Модель — это единый и исчерпывающий источник информации о ваших данных. Она содержит необходимые поля и поведение данных, которые вы храните. Django следует принципу DRY. Цель состоит в том, чтобы определить модель данных в одном месте и автоматически получить из неё всё необходимое.
Это относится и к миграциям: в отличие, например, от Ruby On Rails, миграции полностью выводятся из файла моделей и, по сути, представляют собой историю изменений, которую Django может последовательно применить, чтобы обновить схему базы данных в соответствии с текущими моделями.
В нашем приложении для опросов мы создадим две модели: Question и Choice. У модели Question есть вопрос и дата публикации. У модели Choice есть два поля: текст варианта ответа и количество голосов. Каждый объект Choice связан с объектом Question.
Эти понятия представлены классами Python. Отредактируйте файл polls/models.py так, чтобы он выглядел следующим образом:
polls/models.pyfrom django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField("date published")
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
Здесь каждая модель представлена классом, производным от django.db.models.Model. У каждой модели есть ряд переменных класса, каждая из которых представляет поле базы данных в модели.
Каждое поле представлено экземпляром класса Field — например, CharField для текстовых полей и DateTimeField для даты и времени. Так Django узнаёт, какой тип данных хранится в каждом поле.
Имя каждого экземпляра Field (например, question_text или pub_date) — это имя поля в удобном для машинного чтения формате. Вы будете использовать это значение в коде Python, а база данных будет использовать его в качестве имени столбца.
Чтобы задать понятное человеку имя, можно передать необязательный первый позиционный аргумент в Field. Оно используется в некоторых частях Django, предназначенных для анализа, и одновременно служит документацией. Если этот аргумент не задан, Django использует имя в машинном формате. В этом примере мы задали понятное человеку имя только для Question.pub_date. Для всех остальных полей этой модели в качестве понятного человеку имени подойдёт имя поля в машинном формате.
Для некоторых классов Field требуются аргументы. Например, для CharField необходимо указать значение max_length. Оно используется не только в схеме базы данных, но и при проверке данных, как мы вскоре увидим.
У Field также могут быть различные необязательные аргументы; в данном случае мы задали для votes значение default, равное 0.
Наконец, обратите внимание, что связь задаётся с помощью ForeignKey. Она сообщает Django, что каждый объект Choice связан с одним объектом Question. Django поддерживает все распространённые типы связей в базах данных: «многие к одному», «многие ко многим» и «один к одному».
Активация моделей
Этот небольшой фрагмент кода модели предоставляет Django много информации. Благодаря ей Django может:
- Создать схему базы данных (операторы
CREATE TABLE) для этого приложения. - Создать программный интерфейс Python для доступа к объектам
QuestionиChoiceв базе данных.
Но сначала нужно сообщить проекту, что приложение polls установлено.
Философия
Приложения Django «подключаемые»: их можно использовать в нескольких проектах и распространять, поскольку они не привязаны к конкретной установке Django.
Чтобы включить приложение в проект, нужно добавить ссылку на его класс конфигурации в настройку INSTALLED_APPS. Класс PollsConfig находится в файле polls/apps.py, поэтому его путь с точками — 'polls.apps.PollsConfig'. Отредактируйте файл mysite/settings.py и добавьте этот путь с точками в настройку INSTALLED_APPS. В результате он будет выглядеть так:
mysite/settings.pyINSTALLED_APPS = [
"polls.apps.PollsConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
Теперь Django знает, что нужно включить приложение polls. Выполним ещё одну команду:
$ python manage.py makemigrations polls
...\> py manage.py makemigrations polls
Вы должны увидеть примерно следующее:
Migrations for 'polls':
polls/migrations/0001_initial.py
+ Create model Question
+ Create model Choice
Запуская makemigrations, вы сообщаете Django, что внесли изменения в модели (в данном случае создали новые) и хотите сохранить эти изменения в виде миграции.
С помощью миграций Django сохраняет изменения моделей (а значит, и схемы базы данных) в файлах на диске. При желании вы можете прочитать миграцию для новой модели: это файл polls/migrations/0001_initial.py. Не беспокойтесь: вам не нужно читать такие файлы каждый раз, когда Django создаёт миграцию, но их можно редактировать вручную, если вы захотите самостоятельно изменить способ внесения изменений Django.
Для применения миграций и автоматического управления схемой базы данных существует команда migrate. Мы рассмотрим её чуть позже, а пока посмотрим, какой SQL-код выполнит эта миграция. Команда sqlmigrate принимает имена миграций и выводит соответствующий SQL-код:
$ python manage.py sqlmigrate polls 0001
...\> py manage.py sqlmigrate polls 0001
Вы должны увидеть примерно следующее (для удобства чтения мы изменили форматирование):
BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" (
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL,
"question_id" bigint NOT NULL
);
ALTER TABLE "polls_choice"
ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id"
FOREIGN KEY ("question_id")
REFERENCES "polls_question" ("id")
DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
Обратите внимание на следующее:
- Точный результат зависит от используемой базы данных. Приведённый выше пример создан для PostgreSQL.
- Имена таблиц создаются автоматически: к имени приложения (
polls) добавляется имя модели в нижнем регистре —questionиchoice. (Это поведение можно переопределить.) - Первичные ключи (идентификаторы) добавляются автоматически. (Это тоже можно переопределить.)
- По соглашению Django добавляет
"_id"к имени поля внешнего ключа. (Да, это тоже можно переопределить.) - Связь по внешнему ключу явно задаётся ограничением
FOREIGN KEY. Не беспокойтесь о частяхDEFERRABLE: они сообщают PostgreSQL, что проверку внешнего ключа нужно отложить до конца транзакции. - SQL-код формируется с учётом используемой базы данных, поэтому специальные типы полей для конкретных баз данных, такие как
auto_increment(MySQL),bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY(PostgreSQL) илиinteger primary key autoincrement(SQLite), выбираются автоматически. То же относится к кавычкам вокруг имён полей: например, к использованию двойных или одинарных кавычек. - Команда
sqlmigrateне применяет миграцию к базе данных, а выводит SQL-код на экран, чтобы вы могли увидеть, какие действия, по мнению Django, необходимы. Это полезно, чтобы проверить, что собирается сделать Django, а также если администраторам баз данных требуются SQL-скрипты для внесения изменений.
При желании можно также выполнить команду python manage.py check. Она проверит проект на наличие проблем, не создавая миграций и не обращаясь к базе данных.
Теперь снова запустите migrate, чтобы создать таблицы моделей в базе данных:
$ python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Rendering model states... DONE Applying polls.0001_initial... OK
...\> py manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Rendering model states... DONE
Applying polls.0001_initial... OK
Команда migrate применяет все миграции, которые ещё не были выполнены (Django отслеживает применённые миграции с помощью специальной таблицы в базе данных под названием django_migrations), — то есть синхронизирует изменения моделей со схемой базы данных.
Миграции очень мощны и позволяют менять модели по мере разработки проекта, не удаляя базу данных или таблицы и не создавая их заново. Они предназначены для обновления базы данных без остановки работы и потери данных. Мы подробнее рассмотрим миграции в следующей части руководства, а пока запомните три шага внесения изменений в модели:
- Измените модели (в
models.py). - Запустите
python manage.py makemigrations, чтобы создать миграции для этих изменений. - Запустите
python manage.py migrate, чтобы применить эти изменения к базе данных.
Команды создания и применения миграций разделены, потому что миграции вы будете добавлять в систему контроля версий и включать в приложение. Они упрощают не только разработку, но и работу других разработчиков и развёртывание в рабочей среде.
Полную информацию о возможностях утилиты manage.py см. в документации по django-admin.
Работа с API
Теперь откроем интерактивную оболочку Python и попробуем бесплатный API, который предоставляет Django. Чтобы запустить оболочку Python, выполните следующую команду:
$ python manage.py shell
...\> py manage.py shell
Мы используем эту команду вместо простого ввода «python», потому что manage.py задаёт переменную среды DJANGO_SETTINGS_MODULE, которая указывает Django путь импорта Python к вашему файлу mysite/settings.py. По умолчанию команда shell автоматически импортирует модели из INSTALLED_APPS.
Открыв оболочку, изучите API базы данных:
# No questions are in the system yet. >>> Question.objects.all() <QuerySet []> # Create a new Question. # Support for time zones is enabled in the default settings file, so # Django expects a datetime with tzinfo for pub_date. Use timezone.now() # instead of datetime.datetime.now() and it will do the right thing. >>> from django.utils import timezone >>> q = Question(question_text="What's new?", pub_date=timezone.now()) # Save the object into the database. You have to call save() explicitly. >>> q.save() # Now it has an ID. >>> q.id 1 # Access model field values via Python attributes. >>> q.question_text "What's new?" >>> q.pub_date datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=datetime.UTC) # Change values by changing the attributes, then calling save(). >>> q.question_text = "What's up?" >>> q.save() # objects.all() displays all the questions in the database. >>> Question.objects.all() <QuerySet [<Question: Question object (1)>]>
Подождите. <Question: Question object (1)> — не самое полезное представление этого объекта. Исправим это: отредактируем модель Question (в файле polls/models.py) и добавим метод __str__() в классы Question и Choice:
polls/models.pyfrom django.db import models
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
Методы __str__() важно добавлять в модели не только для собственного удобства при работе с интерактивной оболочкой, но и потому, что представления объектов используются в автоматически создаваемом интерфейсе администрирования Django.
Добавим в эту модель также пользовательский метод:
polls/models.pyimport datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
Обратите внимание на добавление import datetime и from django.utils import
timezone: они нужны для обращения к стандартному модулю Python datetime и связанным с часовыми поясами инструментам Django в django.utils.timezone соответственно. Если вы не знакомы с работой с часовыми поясами в Python, подробнее об этом можно узнать в документации по поддержке часовых поясов.
Сохраните изменения и снова запустите интерактивную оболочку Python, выполнив python manage.py shell:
# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith="What")
<QuerySet [<Question: What's up?>]>
# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>
# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set (defined as "choice_set") to hold the "other side" of a ForeignKey
# relation (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)
# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>
# Create three choices.
>>> q.choice_set.create(choice_text="Not much", votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text="The sky", votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text="Just hacking again", votes=0)
# Choice objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>
# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3
# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith="Just hacking")
>>> c.delete()
Подробнее о связях моделей см. в разделе Доступ к связанным объектам. О том, как использовать двойные подчёркивания для поиска по полям через API, см. в разделе Поиск по полям. Полную информацию об API базы данных см. в справочнике по API базы данных.
Знакомство с Django Admin
Философия
Создание сайтов администрирования, на которых сотрудники или клиенты могут добавлять, изменять и удалять содержимое, — утомительная работа, не требующая особого творчества. Поэтому Django полностью автоматизирует создание интерфейсов администрирования для моделей.
Django был создан в редакции, где чётко разделялись «редакторы содержимого» и «публичный» сайт. Администраторы сайта используют систему для добавления новостей, событий, спортивных результатов и т. д., а это содержимое отображается на публичном сайте. Django решает задачу создания единого интерфейса, с помощью которого администраторы сайта могут редактировать содержимое.
Интерфейс администрирования предназначен не для посетителей сайта, а для его администраторов.
Создание пользователя-администратора
Сначала нужно создать пользователя, который сможет войти на сайт администрирования. Выполните следующую команду:
$ python manage.py createsuperuser
...\> py manage.py createsuperuser
Введите желаемое имя пользователя и нажмите клавишу ввода.
Username: admin
Затем вам предложат ввести адрес электронной почты:
Email address: admin@example.com
Последний шаг — ввод пароля. Вам нужно будет ввести пароль дважды, причём второй раз — для подтверждения первого.
Password: ********** Password (again): ********* Superuser created successfully.
Запуск сервера разработки
Сайт администрирования Django активирован по умолчанию. Запустим сервер разработки и изучим его.
Если сервер не запущен, запустите его следующей командой:
$ python manage.py runserver
...\> py manage.py runserver
Теперь откройте браузер и перейдите по адресу «/admin/» на локальном домене, например http://127.0.0.1:8000/admin/. Вы должны увидеть экран входа в интерфейс администрирования:
Поскольку перевод включён по умолчанию, если вы зададите настройку LANGUAGE_CODE, экран входа будет отображаться на указанном языке (если Django располагает соответствующим переводом).
Вход на сайт администрирования
Теперь попробуйте войти с учётной записью суперпользователя, созданной на предыдущем шаге. Вы должны увидеть главную страницу интерфейса администрирования Django:
Вы увидите несколько типов содержимого, доступного для редактирования: группы и пользователей. Их предоставляет django.contrib.auth — платформа аутентификации, входящая в состав Django.
Добавление приложения опросов в интерфейс администрирования
Но где же наше приложение опросов? На главной странице интерфейса администрирования оно не отображается.
Осталось сделать лишь одно: сообщить интерфейсу администрирования, что для объектов Question предусмотрен интерфейс администрирования. Для этого откройте файл polls/admin.py и отредактируйте его так, чтобы он выглядел следующим образом:
polls/admin.pyfrom django.contrib import admin from .models import Question admin.site.register(Question)
Изучение возможностей интерфейса администрирования
Теперь, когда мы зарегистрировали Question, Django знает, что эту модель нужно отображать на главной странице интерфейса администрирования:
Нажмите «Вопросы». Откроется страница «списка изменений» для вопросов. На ней отображаются все вопросы из базы данных, и можно выбрать вопрос для редактирования. Здесь есть вопрос «Что происходит?», который мы создали ранее:
Нажмите на вопрос «Что происходит?», чтобы отредактировать его:
Обратите внимание на следующее:
- Форма автоматически создаётся на основе модели
Question. - Разным типам полей модели (
DateTimeField,CharField) соответствуют подходящие элементы ввода HTML. Каждый тип поля знает, как отображать себя в интерфейсе администрирования Django. - Для каждого
DateTimeFieldпредусмотрены полезные сочетания с JavaScript. Для дат доступны кнопка «Сегодня» и всплывающий календарь, а для времени — кнопка «Сейчас» и удобное всплывающее меню со списком часто используемых значений времени.
В нижней части страницы доступны несколько вариантов действий:
- Сохранить — сохраняет изменения и возвращает к странице списка изменений для объектов этого типа.
- Сохранить и продолжить редактирование — сохраняет изменения и перезагружает страницу администрирования этого объекта.
- Сохранить и добавить новый — сохраняет изменения и открывает новую пустую форму для объекта этого типа.
- Удалить — открывает страницу подтверждения удаления.
Если значение «Дата публикации» не совпадает со временем, когда вы создали вопрос в Руководстве 1, вероятно, вы забыли задать правильное значение настройки TIME_ZONE. Измените его, перезагрузите страницу и проверьте, что отображается правильное значение.
Измените значение «Дата публикации», нажав кнопки «Сегодня» и «Сейчас». Затем нажмите «Сохранить и продолжить редактирование». После этого нажмите «История» в правом верхнем углу. Откроется страница со списком всех изменений этого объекта, внесённых через интерфейс администрирования Django, с указанием времени изменения и имени пользователя, который его выполнил:
Когда вы освоитесь с API моделей и интерфейсом администрирования, прочитайте часть 3 этого руководства, чтобы узнать, как добавить новые представления в наше приложение опросов.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/intro/tutorial02/