Написание вашей первой Django-приложения, часть 2
Этот учебник начинается там, где закончился Учебник 1. Мы настроим базу данных, создадим вашу первую модель и получим краткое введение в автоматически генерируемый администраторский сайт Django.
Где получить помощь:
Если у вас возникли проблемы с прохождением этого учебника, перейдите к разделу Получение помощи раздела FAQ.
Настройка базы данных
Теперь откройте mysite/settings.py. Это обычный Python-модуль с переменными уровня модуля, представляющими настройки Django.
По умолчанию конфигурация использует SQLite. Если вы новичок в базах данных или просто хотите попробовать Django, это самый простой выбор. SQLite включен в Python, поэтому вам не нужно ничего устанавливать для поддержки вашей базы данных. Однако при запуске вашего первого реального проекта вам, возможно, захочется использовать более масштабируемую базу данных, например PostgreSQL, чтобы избежать проблем со сменой базы данных в будущем.
Если вы хотите использовать другую базу данных, установите соответствующие привязки к базе данных и измените следующие ключи в DATABASES 'default' элементе, чтобы они соответствовали настройкам подключения к вашей базе данных:
-
ENGINE–'django.db.backends.sqlite3','django.db.backends.postgresql','django.db.backends.mysql', или'django.db.backends.oracle'. Другие бэкэнды также доступны. -
NAME– Название вашей базы данных. Если вы используете SQLite, база данных будет файлом на вашем компьютере; в этом случаеNAMEдолжен представлять собой полный абсолютный путь, включая имя файла, этого файла. Значение по умолчанию,BASE_DIR / 'db.sqlite3', будет хранить файл в каталоге вашего проекта.
Если вы не используете SQLite в качестве вашей базы данных, необходимо добавить дополнительные настройки, такие как USER, PASSWORD и HOST. Для получения более подробной информации см. справочную документацию для DATABASES.
Для баз данных, отличных от SQLite
Если вы используете базу данных, отличную от SQLite, убедитесь, что вы создали базу данных к этому моменту. Сделайте это с помощью «CREATE DATABASE database_name;» в интерактивном приглашении вашей базы данных.
Также убедитесь, что у пользователя базы данных, указанного в mysite/settings.py, есть права на создание базы данных. Это позволяет автоматически создавать тестовую базу данных, которая понадобится в последующем учебнике.
Если вы используете SQLite, вам не нужно ничего создавать заранее — файл базы данных будет создан автоматически при необходимости.
При редактировании 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 также может иметь различные необязательные аргументы; в этом случае мы установили значение default для votes в 0.
Наконец, обратите внимание, что отношение определено с помощью ForeignKey. Это говорит Django, что каждый Choice связан с одним Question. Django поддерживает все распространённые отношения в базах данных: многие-ко-многим, многие-к-одному и один-к-одному.
Активация моделей
Этот небольшой фрагмент кода модели предоставляет Django много информации. С его помощью Django может:
- Создать схему базы данных (
CREATE TABLEинструкции) для этого приложения. - Создать Python API для доступа к объектам
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. (Вы можете настроить это поведение.) - Первичные ключи (ID) добавляются автоматически. (Вы тоже можете это настроить.)
- Согласно соглашению, Django добавляет
"_id"к имени поля внешнего ключа. (Да, вы можете это настроить.) - Отношение внешнего ключа явно указывается с помощью ограничения
FOREIGN KEY. Не беспокойтесь о частяхDEFERRABLE; это говорит PostgreSQL о том, что внешние ключи не должны применяться до конца транзакции. - Это настраивается для используемой базы данных, поэтому типы полей, специфичные для базы данных, такие как
auto_increment(MySQL),bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY(PostgreSQL) илиinteger primary key autoincrement(SQLite), обрабатываются автоматически. То же самое относится к цитированию имён полей — например, с использованием двойных или одинарных кавычек. - Команда
sqlmigrateфактически не запускает миграцию в вашей базе данных — вместо этого она выводит SQL на экран, чтобы вы могли увидеть, какой 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, чтобы применить эти изменения к базе данных.
Причина, по которой для создания и применения миграций существуют отдельные команды, заключается в том, что вы будете коммитить миграции в свою систему контроля версий и отправлять их вместе с вашим приложением; они не только упрощают вашу разработку, но также могут использоваться другими разработчиками и в производстве.
Прочитайте документацию django-admin, чтобы получить полную информацию о том, что может делать утилита manage.py.
Работа с API
Теперь давайте перейдём к интерактивной оболочке Python и поэкспериментируем с бесплатным API, предоставляемым Django. Для запуска оболочки Python используйте эту команду:
$ python manage.py shell
...\> py manage.py shell
Мы используем это вместо простого набора «python», потому что manage.py устанавливает переменную среды DJANGO_SETTINGS_MODULE, которая даёт Django путь импорта Python к вашему файлу mysite/settings.py.
После входа в оболочку изучите API базы данных:
>>> from polls.models import Choice, Question # Import the model classes we just wrote. # 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.timezone.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 ещё раз:
>>> from polls.models import Choice, Question
# 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 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
Введите желаемое имя пользователя и нажмите Enter.
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.
Сделать приложение poll доступным для редактирования в администрировании
Но где наше приложение poll? Оно не отображается на главной странице администрирования.
Осталось сделать только одно: нужно сказать администрированию, что 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-shortcuts. Даты получают shortcut «Сегодня» и всплывающее окно календаря, а время получает shortcut «Сейчас» и удобное всплывающее окно, которое перечисляет часто вводимые времена.
В нижней части страницы представлены несколько вариантов:
- Сохранить — сохраняет изменения и возвращается на страницу списка изменений для этого типа объектов.
- Сохранить и продолжить редактирование — сохраняет изменения и перезагружает страницу администрирования для этого объекта.
- Сохранить и добавить ещё — сохраняет изменения и загружает новую, пустую форму для этого типа объекта.
- Удалить — отображает страницу подтверждения удаления.
Если значение «Дата публикации» не соответствует времени, когда вы создали вопрос в Учебнике 1, это, вероятно, означает, что вы забыли установить правильное значение для параметра TIME_ZONE. Измените его, перезагрузите страницу и проверьте, что отображается правильное значение.
Измените «Дата публикации», нажав на shortcuts «Сегодня» и «Сейчас». Затем нажмите «Сохранить и продолжить редактирование». Затем нажмите «История» в верхнем правом углу. Вы увидите страницу со списком всех изменений, внесённых в этот объект через Django администрирование, с отметкой времени и именем пользователя, который внес изменение:
Когда вы освоитесь с API моделей и ознакомитесь с админ-панелью, прочитайте часть 3 этого учебника, чтобы узнать, как добавить дополнительные представления в наше приложение poll.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.2/intro/tutorial02/