Написание вашего первого приложения Django, часть 2
Этот учебник продолжается там, где закончился Урок 1. Мы настроим базу данных, создадим вашу первую модель и получим краткое введение в автоматически генерируемый административный интерфейс Django.
Где получить помощь:
Если у вас возникли проблемы с этим учебником, обратитесь к разделу Получение помощи раздела FAQ.
Настройка базы данных
Теперь откройте 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; (MariaDB, 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.
Наконец, обратите внимание, что отношение определяется с помощью 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 Question
- Create model 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 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 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 администрирования
Философия
Генерация сайтов администратора для вашего персонала или клиентов для добавления, изменения и удаления контента — утомительная работа, которая не требует много креативности. По этой причине 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/. Вы должны увидеть экран входа в систему администратора:
Поскольку перевод включен по умолчанию, если вы установите LANGUAGE_CODE, экран входа в систему будет отображаться на заданном языке (если 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/3.0/intro/tutorial02/