Создание вашего первого приложения Django, часть 2
Этот учебник начинается там, где закончился Учебник 1. Мы настроим базу данных, создадим вашу первую модель и получим краткое введение в автоматически генерируемый административный интерфейс Django.
Настройка базы данных
Теперь откройте 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должен содержать полный абсолютный путь, включая имя файла, этого файла. Значение по умолчаниюos.path.join(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
Команда migrate анализирует настройку INSTALLED_APPS и создает необходимые таблицы базы данных в соответствии с настройками базы данных в вашем файле mysite/settings.py и миграциями базы данных, поставляемыми с приложением (мы рассмотрим их позже). Вы увидите сообщение для каждой применённой миграции. Если вы заинтересованы, запустите клиент командной строки для вашей базы данных и введите \dt (PostgreSQL), SHOW TABLES; (MySQL), .schema (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 так, чтобы он выглядел так:
from 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инструкции) для этого приложения. - Создать API доступа к базам данных Python для доступа к объектам
QuestionиChoice.
Но сначала нам нужно сообщить нашему проекту, что приложение polls установлено.
Философия
Приложения Django «подключаемы»: вы можете использовать приложение в нескольких проектах, а также распространять приложения, поскольку они не должны быть привязаны к конкретной установке Django.
Для включения приложения в наш проект нам необходимо добавить ссылку на его конфигурационный класс в настройку INSTALLED_APPS. Класс PollsConfig находится в файле polls/apps.py, поэтому его путь с точками – 'polls.apps.PollsConfig'. Измените файл mysite/settings.py и добавьте этот путь с точками в настройку INSTALLED_APPS. Он будет выглядеть так:
INSTALLED_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
Вы увидите что-то подобное:
Migrations for 'polls':
polls/migrations/0001_initial.py:
- Create model Choice
- Create model Question
- Add field question to choice
Выполняя команду makemigrations, вы сообщаете Django, что внесли изменения в свои модели (в данном случае, создали новые) и хотите, чтобы изменения были сохранены как миграция.
Миграции – это способ, которым Django сохраняет изменения в ваших моделях (и, следовательно, схеме вашей базы данных) – они просто файлы на диске. Вы можете прочитать миграцию для новой модели, если хотите; это файл polls/migrations/0001_initial.py. Не беспокойтесь, от вас не ожидается чтение их каждый раз, когда Django делает миграцию, но они предназначены для редактирования человеком, если вы хотите вручную настроить, как Django изменяет вещи.
Существует команда, которая будет выполнять миграции для вас и управлять вашей схемой базы данных автоматически – это migrate, и мы подойдём к ней немного позже – но сначала давайте посмотрим, какой SQL будет выполнена этой миграцией. Команда sqlmigrate принимает имена миграций и возвращает их SQL:
$ python manage.py sqlmigrate polls 0001
Вы должны увидеть что-то подобное (мы переформатировали его для лучшей читаемости):
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
--
-- Create model Question
--
CREATE TABLE "polls_question" (
"id" serial NOT NULL PRIMARY KEY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL;
ALTER TABLE "polls_choice" ALTER COLUMN "question_id" DROP DEFAULT;
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");
ALTER TABLE "polls_choice"
ADD CONSTRAINT "polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id"
FOREIGN KEY ("question_id")
REFERENCES "polls_question" ("id")
DEFERRABLE INITIALLY DEFERRED;
COMMIT;
Обратите внимание на следующее:
- Точный вывод будет зависеть от используемой вами базы данных. Приведённый выше пример сгенерирован для PostgreSQL.
- Имена таблиц автоматически генерируются путём объединения имени приложения (
polls) и имени модели в нижнем регистре –questionиchoice. (Вы можете настроить это поведение.) - Первичные ключи (ID) добавляются автоматически. (Вы можете настроить это тоже.)
- По соглашению, Django добавляет
"_id"к имени поля внешнего ключа. (Да, вы можете настроить это тоже.) - Связь внешнего ключа явно указывается с помощью ограничения
FOREIGN KEY. Не беспокойтесь о частяхDEFERRABLE; это просто говорит PostgreSQL не применять ограничение внешнего ключа до конца транзакции. - Она настраивается под используемую вами базу данных, поэтому типы полей, специфичные для базы данных, такие как
auto_increment(MySQL),serial(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
Команда 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
Мы используем это вместо простого набора «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=<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:
from 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.
Обратите внимание, что это обычные методы Python. Давайте добавим пользовательский метод, просто для демонстрации:
import 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
Введите желаемое имя пользователя и нажмите Enter.
Username: admin
Затем вам будет предложено ввести желаемый адрес электронной почты:
Email address: admin@example.com
Последний шаг – ввод пароля. Вам будет предложено ввести пароль дважды, второй раз для подтверждения первого.
Password: ********** Password (again): ********* Superuser created successfully.
Запуск сервера разработки
Сайт администрирования Django активирован по умолчанию. Давайте запустим сервер разработки и исследуем его.
Если сервер не запущен, запустите его так:
$ python manage.py runserver
Теперь откройте веб-браузер и перейдите по адресу «/admin/» на вашем локальном домене – например, http://127.0.0.1:8000/admin/. Вы должны увидеть экран входа в администрирование:
Поскольку перевод включен по умолчанию, экран входа может быть отображён на вашем языке, в зависимости от настроек браузера и наличия перевода для этого языка в Django.
Вход в административный сайт
Теперь попробуйте войти в систему с учетной записью суперпользователя, которую вы создали на предыдущем шаге. Вы должны увидеть главную страницу администрирования Django:
Вы должны увидеть несколько типов редактируемого контента: группы и пользователи. Они предоставляются django.contrib.auth, фреймворком аутентификации, поставляемым с Django.
Сделайте приложение poll доступным для изменения в администрировании
Но где наше приложение poll? Оно не отображается на главной странице администрирования.
Нужно сделать всего одно: сообщить администрированию, что Question объекты имеют интерфейс администрирования. Для этого откройте файл polls/admin.py и измените его так:
from 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 моделей и ознакомитесь с сайтом администрирования, прочтите третью часть этого руководства, чтобы узнать, как добавить дополнительные представления в наше приложение polls.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.0/intro/tutorial02/