Создание первого приложения на Django, часть 2¶
Этот учебник начинается с момента, на которым мы остановились в Tutorial 1 остановился. Здесь мы настроим базу данных, создадим первую модель и быстро познакомимся с автоматически генерируемым сайтом администрирования Django.
Где получить помощь:
Если у вас возникли проблемы с прохождением этого руководства, перейдите в раздел часто задаваемых вопросов Получение справки.
Настройка базы данных¶
Теперь откройте mysite/settings.py
. Это обычный модуль Python с переменными уровня модуля, представляющими настройки Django.
По умолчанию в конфигурации используется SQLite. Если вы новичок в базах данных или просто хотите попробовать Django, это самый простой выбор. SQLite включен в Python, поэтому вам не нужно устанавливать что-либо еще для поддержки вашей базы данных. Однако при запуске первого реального проекта вы можете использовать более масштабируемую базу данных, такую как PostgreSQL, чтобы избежать проблем с переключением баз данных в будущем.
Если вы хотите использовать другую базу данных, установите соответствующую bindings и измените следующие ключи в параметре 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
, имеет права на создание базы данных. Это позволяет автоматически создавать test database, которая понадобится в следующем уроке.
Если вы используете 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), .schema
(SQLite), или SELECT TABLE_NAME FROM USER_TABLES;
(Oracle) для отображения таблиц, созданных Django.
Для минималистов
Как мы уже говорили выше, стандартные приложения включены для общего случая, но они нужны не всем. Если вам не нужны какие-либо или все из них, не стесняйтесь комментировать или удалять соответствующие строки из INSTALLED_APPS
перед запуском migrate
. Команда migrate
запускает миграцию только для приложений в INSTALLED_APPS
.
Создание моделей¶
Теперь мы определим ваши модели – по сути, структуру вашей базы данных с дополнительными метаданными.
Философия
A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Django follows the DRY Principle. The goal is to define your data model in one place and automatically derive things from it.
Это включает в себя миграции - в отличие от 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
для datetime. Это сообщает Django, какой тип данных содержит каждое поле.
Имя каждого экземпляра Field
(например, question_text
или pub_date
) – это имя поля в машинно-удобном формате. Вы будете использовать это значение в своем коде Python, а ваша база данных будет использовать его в качестве имени столбца.
Вы можете использовать необязательный первый позиционный аргумент для Field
для обозначения понятного человеку названия. Это используется в паре интроспективных частей Django, и дублируется как документация. Если это поле не указано, Django будет использовать машиночитаемое имя. В этом примере мы определили только удобочитаемое имя для Question.pub_date
. Для всех других полей в этой модели, машиночитаемое имя поля будет достаточно в качестве его удобочитаемого имени.
Некоторые классы Field
имеют обязательные аргументы. CharField
, например, требует, чтобы вы передали ему аргумент max_length
. Это используется не только в схеме базы данных, но и при проверке, как мы скоро увидим.
Field
также может иметь различные необязательные аргументы. В этом случае мы установили для default
значение voice
в 0.
Наконец, обратите внимание, что связь определена с использованием ForeignKey
. Это говорит Django, что каждый Choice
связан с одним Question
. Django поддерживает все общие отношения базы данных: многие-к-одному, многие-ко-многим и один-к-одному.
Активация моделей¶
Этот небольшой кусочек кода модели дает Django много информации. С его помощью Django может:
- Создать схему базы данных (оператор
CREATE TABLE
) для этого приложения. - Создать API доступа к базе данных Python для доступа к объектам
Question
иChoice
.
Но сначала нам нужно сообщить нашему проекту, что установлено приложение polls
.
Философия
Приложения Django являются «подключаемыми»: вы можете использовать приложение в нескольких проектах и распространять приложения, потому что они не должны быть привязаны к конкретной установке Django.
Чтобы включить приложение в наш проект, нужно добавить ссылку на его класс конфигурации в настройке INSTALLED_APPS
. Класс PlayersConfig
находится в файле 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
...\> 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 их создает, но они предназначены для редактирования человеком, если вы хотите вручную что-то изменить.
Есть команда, которая будет запускать миграции для вас и автоматически управлять схемой вашей базы данных - она называется 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" serial NOT NULL PRIMARY KEY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL,
"question_id" integer 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 не применять внешний ключ до конца транзакции. - Он адаптирован к используемой вами базе данных, поэтому обрабатываются специфичные для базы данных типы полей, такие как
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
...\> 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=<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.
Давайте также добавим пользовательский метод к этой модели:
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)
Обратите внимание на добавление 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¶
Философия
Создание сайтов администратора для ваших сотрудников или клиентов для добавления, изменения и удаления контента - это утомительная работа, которая не требует большого творческого подхода. По этой причине 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/. Вы должны увидеть экран входа администратора:
Поскольку translation включен по умолчанию, если вы установите LANGUAGE_CODE
, экран входа в систему будет отображаться на заданном языке (если у Django есть соответствующие переводы).
Вход в админку¶
Теперь попробуйте войти в систему с учетной записью суперпользователя, которую вы создали на предыдущем шаге. Вы должны увидеть главную страницу админки Django:
Вы должны увидеть несколько типов редактируемого контента: группы и пользователи. Они предоставляются django.contrib.auth
, инфраструктурой аутентификации, поставляемой Django.
Добавление своего приложения в админку¶
Но где наше приложение для голосования? Оно не отображается на главной странице админки.
Осталось сделать еще одно дело: нужно сообщить админке, что у объектов Question
есть интерфейс администратора. Для этого откройте файл polls/admin.py
и отредактируйте его следующим образом:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
Изучите функциональность админки¶
Теперь, когда мы зарегистрировали Question
, Django знает, что он должен отображаться на главной странице:
Нажмите «Questions». Теперь вы находитесь на странице «Список изменений» для вопросов. На этой странице отображаются все вопросы в базе данных, и вы можете выбрать один из них, чтобы изменить его. Там есть вопрос «What’s up?», который мы создали ранее:
Нажмите «What’s up?» для его редактирования:
Что следует отметить здесь:
- Форма автоматически генерируется из модели
Question
. - Различные типы полей модели (
DateTimeField
,CharField
) соответствуют своему виджету ввода HTML. Каждый тип поля знает, как отобразить себя в админке Django. - Каждый
DateTimeField
получает ярлыки JavaScript. Даты получают ярлык «Сегодня» и всплывающее окно календаря, а время - ярлык «Сейчас» и удобное всплывающее окно, в котором перечислены часто вводимые времена.
В нижней части страницы вы найдете несколько опций:
- Save - сохраняет изменения и возвращает на страницу списка изменений для этого типа объекта.
- Сохранить и продолжить редактирование - сохраняет изменения и перезагружает страницу администратора для этого объекта.
- Сохранить и добавить еще один - сохраняет изменения и загружает новую, пустую форму для этого типа объекта.
- Удалить - отображает страницу подтверждения удаления.
Если значение «Date published» не соответствует времени, когда вы создали вопрос в Части 1, это, вероятно, означает, что вы забыли установить правильное значение для настройки TIME_ZONE
. Измените его, перезагрузите страницу и убедитесь, что отображается правильное значение.
Измените «Дата публикации», нажав на ярлыки «Сегодня» и «Сейчас». Затем нажмите «Сохранить и продолжить редактирование». Затем нажмите «История» в правом верхнем углу. Вы увидите страницу со списком всех изменений, внесенных в этот объект через администратора Django, с отметкой времени и именем пользователя, который внес изменение:
Если вы знакомы с API моделей и ознакомились с сайтом администратора, прочитайте часть 3, чтобы узнать, как добавить больше отображений (функций) в наше приложение для опросов.