Создаём своё первое приложение с Django, часть 2¶
This tutorial begins where Tutorial 1 left off. We’ll setup the database, create your first model, and get a quick introduction to Django’s automatically-generated admin site.
Где получить помощь:
При наличии проблем с данной инструкцией, пожалуйста, обратитесь к разделу FAQ Получение помощи.
Настройка базы данных¶
Теперь откроем файл mysite/settings.py. Это обычный модуль Python с набором переменных, которые представляют настройки Django.
By default, the configuration uses SQLite. If you’re new to databases, or you’re just interested in trying Django, this is the easiest choice. SQLite is included in Python, so you won’t need to install anything else to support your database. When starting your first real project, however, you may want to use a more scalable database like PostgreSQL, to avoid database-switching headaches down the road.
Если вы хотите использовать другую базу данных, установите необходимые библиотеки и поменяйте следующие ключи в элементе 'default' настройки DATABASES, чтобы они соответсвовали настройкам подключения к вашей базе данных:
ENGINE– один из'django.db.backends.sqlite3','django.db.backends.postgresql','django.db.backends.mysql'или'django.db.backends.oracle'. Также доступны дополнительные бэкенды.NAME– The name of your database. If you’re using SQLite, the database will be a file on your computer; in that case,NAMEshould be the full absolute path, including filename, of that file. The default value,BASE_DIR / 'db.sqlite3', will store the file in your project directory.
Если вы используете не SQLite,вам необходимо указать дополнительно USER, PASSWORD и HOST. Подробности смотрите в описании DATABASES.
Для других баз данных, кроме SQLite
Если вы используете не SQLite, убедитесь, что вы создали базу данных. Вы можете сделать это, выполнив «CREATE DATABASE database_name;» в консоли вашей базы данных.
Также обратите внимание, что пользователь базы данных из mysite/settings.py имеет права создавать базу данных(«create database»). Это позволит автоматически создавать тестовую базу данных.
If you’re using SQLite, you don’t need to create anything beforehand - the database file will be created automatically when it is needed.
Отредактируйте mysite/settings.py и укажите в TIME_ZONE ваш часовой пояс.
Также обратите внимание на настройку INSTALLED_APPS в начале файла. Она содержит названия всех приложений 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
The migrate command looks at the INSTALLED_APPS setting
and creates any necessary database tables according to the database settings
in your mysite/settings.py file and the database migrations shipped
with the app (we’ll cover those later). You’ll see a message for each
migration it applies. If you’re interested, run the command-line client for your
database and type \dt (PostgreSQL), SHOW TABLES; (MariaDB, MySQL),
.schema (SQLite), or SELECT TABLE_NAME FROM USER_TABLES; (Oracle) to
display the tables Django created.
Для минималистов
Как мы уже говорили ранее, приложения по умолчанию удобны для типовых проектов, но не для всех. Если вы не нуждаетесь в некоторых или во всех, закомментируйте или удалите соответствующие строки в INSTALLED_APPS перед запуском migrate. Команда migrate выполнит миграции только для приложений в INSTALLED_APPS.
Создание моделей¶
Теперь создадим ваши модели – по сути структуру вашей базы данных с дополнительными мета-данными.
Философия
Модель — это основной источник данных. Она содержит информацию о наборе полей и о поведении данных, которые вы храните. Django следует принципу DRY. Его цель в определении вашей модели данных в одном месте и автоматической генерации остального на её основе.
Это включает в себя и миграции. В отличии от Ruby On Rails, например, миграции полностью создаются на основе вашего файла моделей и, по своей сути, являются историей того, как Django изменит схему вашей базы данных, чтобы соответствовать текущему состоянию ваших моделей.
В нашем приложении голосования, мы создадим две модели: Question и Choice. Question содержит вопрос и дату публикации. Choice содержит два поля: текст ответа и подсчёт голосов. Каждый объект Choice связан с объектом Question.
Эти понятия представлены в виде классов Python. Отредактируйте файл polls/models.py, чтобы он выглядел таким образом:
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 ) это название поля, в «машинном»(machine-friendly) формате. Вы будете использовать эти названия в коде, а база данных будет использовать их как названия колонок.
Вы можете использовать первый необязательный аргумент конструктора класса 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.py¶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. (Вы можете переопределить это.)Первичные ключи (ID) добавлены автоматически. (Вы можете переопределить и это.)
Django добавляет
"_id"к названию внешнего ключа. (Да, вы можете переопределить и это.)Связь явно определена через
FOREIGN KEYconstraint. Не волнуйтесь о части сDEFERRABLE, это просто указание для PostgreSQL не применять ограниченияFOREIGN KEYдо окончания транзакции.It’s tailored to the database you’re using, so database-specific field types such as
auto_increment(MySQL),serial(PostgreSQL), orinteger primary key autoincrement(SQLite) are handled for you automatically. Same goes for the quoting of field names – e.g., using double quotes or single quotes.Команда
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 путь импорта для файла mysite/settings.py.
Once you’re in the shell, explore the database 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:
polls/models.py¶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 использует строковое представление объекта в интерфейсе администратора.
Давайте также добавим свой метод в эту модель:
polls/models.py¶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 работает с временными зонами, вы можете прочитать об этом в разделе о поддержке временных зон.
Save these changes and start a new Python interactive shell by running
python manage.py shell again:
>>> 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 для работы с базой данных содержится в соответствующем разделе.
Введение в интерфейс администратор Django¶
Философия
Создание интерфейса администратора для добавления, изменения и удаления содержимого сайта – в основном скучная не креативная задача. Django значительно автоматизирует и упрощает эту задачу.
Django создавался для новостных сайтов, у которых есть разделение между публичными страницами и интерфейсом администратора. Менеджеры используют последний для добавления новостей и другого содержимого сайта, это содержимое отображается на сайте. Django позволяет легко создать универсальный интерфейс для редактирования содержимого сайта.
Интерфейс администратора не предназначен для использования пользователями. Он создан для менеджеров и администраторов сайта.
Создание суперпользователя¶
Первым делом необходимо создать пользователя, который может заходить на интерфейс администратора. Выполните следующую команду:
$ python manage.py createsuperuser
...\> py manage.py createsuperuser
Введите имя пользователя и нажмите Enter.
Username: admin
Теперь введите email:
Email address: admin@example.com
И наконец введите пароль. Вас спросят об этом дважды, чтобы проверить правильность его ввода.
Password: **********
Password (again): *********
Superuser created successfully.
Запускаем сервер для разработки¶
Интерфейс администратора включен по умолчанию. Давайте запустим встроенный сервер для разработки и посмотрим на него.
Если сервер не запущен, выполните:
$ python manage.py runserver
...\> py manage.py runserver
Откроем «/admin/» локального домена в браузере – например, http://127.0.0.1:8000/admin/. Вы должны увидеть страницу авторизации интерфейса администратора:
Так как перевод включен по-умолчанию, если вы измените LANGUAGE_CODE, форма логина будет отбражаться в указанном языке (Если в Django есть переводы для этого языка).
Заходим в интерфейс администратора¶
Теперь попробуйте войти в админку. Вы должны видеть следующую страницу Django:
Вы должны увидеть несколько разделов: группы и пользователи. Они предоставлены приложением авторизации Django django.contrib.auth.
Добавим приложение голосования в интерфейс администратора¶
А где же наше приложение голосования? Оно не отображается в интерфейсе администратора.
Надо сделать ещё одно: нам надо указать, что объекты модели Question должны редактироваться в интерфейсе администратора. Для этого создадим файл polls/admin.py, и отредактируем следующим образом:
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 поля. Каждое поле знает как отобразить себя в интерфейсе администратора.К полям
DateTimeFieldдобавлен JavaScript виджет. Для даты добавлена кнопка «Сегодня» и календарь, для времени добавлена кнопка «Сейчас» и список распространенных значений.
В нижней части страницы мы видим несколько кнопок:
Save – сохранить изменения и вернуться на страницу списка объектов.
Save and continue editing – сохранить изменения и снова загрузить страницу редактирования текущего объекта.
Save and add another – Сохранить изменения и перейти на страницу создания нового объекта.
Delete – Показывает страницу подтверждения удаления.
Если значение «Date published» не совпадает с временем создания объекта в Части 1 учебника, возможно, вы неверно определили настройку TIME_ZONE. Измените ее и перезагрузите страницу.
Измените «Date published», нажав «Today» и «Now». Затем нажмите «Save and continue editing.» Теперь нажмите «History» в правом верхнем углу страницы. Вы увидите все изменения объекта, сделанные через интерфейс администратора, время изменений и пользователя, который их сделал:
Если вы освоили интерфейс администратора, переходите к третьей части этого учебника.