Создание вашей первой 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
...\> py 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
...\> py 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
...\> py 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
...\> 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)
Обратите внимание на добавление import datetime и from django.utils import
timezone, чтобы обратиться к стандартному модулю Python datetime и инструментам Django, связанным с часовыми поясами, в django.utils.timezone соответственно. Если вы не знакомы с обработкой часовых поясов в Python, вы можете узнать больше в документации по поддержке часовых поясов.
Сохраните эти изменения и запустите новую интерактивную оболочку Python, выполнив python manage.py shell ещё раз:
>>> from polls.models import Choice, Question
# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>
# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>
# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)
# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>
# Create three choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
# Choice objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>
# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3
# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
Для получения дополнительной информации об отношениях моделей см. Доступ к связанным объектам. Для получения дополнительной информации о том, как использовать двойные подчёркивания для выполнения поисков по полям через API, см. Поиск по полям. Для получения полной информации об API базы данных см. нашу справку по API базы данных.
Представление Django Admin
Философия
Генерация сайтов администрирования для вашего персонала или клиентов для добавления, изменения и удаления контента — это утомительная работа, которая не требует много креативности. По этой причине Django полностью автоматизирует создание интерфейсов администрирования для моделей.
Django был написан в новостной среде с очень четким разделением между «авторами контента» и «публичным» сайтом. Администраторы сайта используют систему для добавления новостей, событий, спортивных результатов и т. д., а этот контент отображается на публичном сайте. Django решает проблему создания единого интерфейса для администраторов сайта для редактирования контента.
Админ-панель не предназначена для использования посетителями сайта. Она предназначена для менеджеров сайта.
Создание пользователя администратора
Сначала нам нужно создать пользователя, который может войти в админ-панель. Выполните следующую команду:
$ python manage.py createsuperuser
...\> py manage.py createsuperuser
Введите желаемое имя пользователя и нажмите Enter.
Username: admin
Затем вам будет предложено ввести желаемый адрес электронной почты:
Email address: admin@example.com
Последний шаг — ввести пароль. Вам будет предложено дважды ввести свой пароль, во второй раз для подтверждения первого.
Password: ********** Password (again): ********* Superuser created successfully.
Запуск сервера разработки
Админ-панель Django активирована по умолчанию. Давайте запустим сервер разработки и исследуем его.
Если сервер не запущен, запустите его следующим образом:
$ python manage.py runserver
...\> py manage.py runserver
Теперь откройте веб-браузер и перейдите по адресу «/admin/» на вашем локальном домене — например, http://127.0.0.1:8000/admin/. Вы должны увидеть экран входа в админ-панель:
Поскольку перевод включен по умолчанию, экран входа может быть отображен на вашем языке в зависимости от настроек вашего браузера и наличия перевода для этого языка в 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 знает, что оно должно отображаться на главной странице админ-панели:
Нажмите «Вопросы». Теперь вы на странице «список изменений» для вопросов. Эта страница отображает все вопросы в базе данных и позволяет вам выбрать один для изменения. Там есть вопрос «Что нового?» , который мы создали ранее:
Нажмите на вопрос «Что нового?» для редактирования:
Следует отметить:
- Форма автоматически генерируется из модели
Question. - Разные типы полей модели (
DateTimeField,CharField) соответствуют соответствующему HTML-элементу ввода. Каждый тип поля знает, как отобразить себя в админ-панели Django. - Каждое поле
DateTimeFieldполучает бесплатные JavaScript-сокращения. Даты получают сокращение «Сегодня» и всплывающую календарную панель, а время получает сокращение «Сейчас» и удобную всплывающую панель, которая перечисляет часто вводимое время.
В нижней части страницы у вас есть несколько вариантов:
- Сохранить — сохраняет изменения и возвращается к странице списка изменений для этого типа объекта.
- Сохранить и продолжить редактирование — сохраняет изменения и перезагружает страницу администрирования для этого объекта.
- Сохранить и добавить другой — сохраняет изменения и загружает новую пустую форму для этого типа объекта.
- Удалить — отображает страницу подтверждения удаления.
Если значение «Дата публикации» не совпадает со временем, когда вы создали вопрос в Уроке 1, это, вероятно, означает, что вы забыли установить правильное значение для параметра TIME_ZONE. Измените его, перезагрузите страницу и проверьте, что появляется правильное значение.
Измените «Дата публикации», щелкнув сокращения «Сегодня» и «Сейчас». Затем нажмите «Сохранить и продолжить редактирование». Затем нажмите «История» в правом верхнем углу. Вы увидите страницу, на которой перечислены все изменения, внесенные в этот объект через админ-панель Django, со временем и именем пользователя, который внес изменение:
Когда вы будете готовы работать с API моделей и ознакомитесь с админ-панелью, прочитайте часть 3 этого руководства, чтобы узнать, как добавить больше представлений в наше приложение опросов.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.2/intro/tutorial02/