Создание вашей первой 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 (Don't Repeat Yourself). Цель заключается в определении вашей модели данных в одном месте и автоматическом выводе данных из неё.
Это включает в себя миграции — в отличие от 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операторы) для этого приложения. - Создать Python API доступа к базам данных для работы с объектами
QuestionиChoice.
Но сначала нам нужно сказать нашему проекту, что приложение polls установлено.
Философия
Приложения Django «подключаемые»: Вы можете использовать приложение в нескольких проектах, а также распространять приложения, так как они не привязаны к конкретной установке Django.
Отредактируйте файл mysite/settings.py ещё раз и измените настройку INSTALLED_APPS так, чтобы она включала строку 'polls.apps.PollsConfig'. Она будет выглядеть так:
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':
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, contenttypes, polls, auth, 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.
Обход manage.py
Если вы предпочитаете не использовать manage.py, не проблема. Просто установите переменную среды DJANGO_SETTINGS_MODULE в значение mysite.settings, запустите обычную оболочку Python и настройте Django:
>>> import django >>> django.setup()
Если это вызывает AttributeError, вероятно, вы используете версию Django, которая не соответствует версии данного учебника. Вам нужно либо переключиться на более старую версию учебника, либо на новую версию Django.
Вы должны запустить python из той же директории, что и manage.py, или убедиться, что эта директория находится на пути Python, чтобы import mysite работал.
Дополнительную информацию об этом можно найти в документации django-admin.
После того, как вы окажетесь в оболочке, изучите API базы данных:
>>> from polls.models import Question, Choice # Import the model classes we just wrote. # No questions are in the system yet. >>> Question.objects.all() [] # 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. Note that this might say "1L" instead of "1", depending # on which database you're using. That's no biggie; it just means your # database backend prefers to return integers as Python long integer # objects. >>> 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() [<Question: Question object>]
Постойте. <Question: Question object> — совершенно бесполезное представление этого объекта. Давайте исправим это, отредактировав модель Question (в файле polls/models.py) и добавив метод __str__() как в Question, так и в Choice.
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible # only if you need to support Python 2
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
@python_2_unicode_compatible # only if you need to support Python 2
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 Question, Choice
# Make sure our __str__() addition worked.
>>> Question.objects.all()
[<Question: What's up?>]
# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
[<Question: What's up?>]
>>> Question.objects.filter(question_text__startswith='What')
[<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()
[]
# 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()
[<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)
[<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
Введите желаемое имя пользователя и нажмите 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 моделей и ознакомитесь со страницей администрирования, прочтите третью часть данного руководства, чтобы узнать, как добавить больше представлений в наше приложение poll.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.9/intro/tutorial02/