Написание вашей первой 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должен быть полным абсолютным путем, включая имя файла, этого файла. Значение по умолчанию,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), .tables (SQLite) или SELECT TABLE_NAME FROM USER_TABLES; (Oracle), чтобы отобразить созданные Django-таблицы.
Для минималистов
Как мы упоминали выше, приложения по умолчанию включены для общего случая, но не всем они нужны. Если вам не нужны все или некоторые из них, можете закомментировать или удалить соответствующую строку(и) из INSTALLED_APPS перед запуском команды migrate. Команда migrate будет запускать миграции только для приложений в INSTALLED_APPS.
Создание моделей
Теперь мы определим ваши модели – по существу, вашу структуру базы данных с дополнительными метаданными.
Философия
Модель является единственным, определяющим источником информации о ваших данных. Она содержит основные поля и поведение хранимых данных. Django следует принципу DRY. Цель состоит в том, чтобы определить вашу модель данных в одном месте и автоматически вывести из нее все необходимое.
Это включает в себя миграции – в отличие от Ruby On Rails, например, миграции полностью выведены из вашего файла моделей и по существу представляют историю, по которой Django может переходить для обновления схемы вашей базы данных для соответствия вашим текущим моделям.
В нашем приложении опросов мы создадим две модели: Question и Choice. Опрос имеет вопрос и дату публикации. Выбор имеет текст выбора и счет голосов. Каждый выбор связан с опросом.
Эти концепции представлены классами 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 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, чтобы применить эти изменения к базе данных.
Причина, по которой для создания и применения миграций существуют отдельные команды, заключается в том, что вы будете коммитить миграции в вашу систему управления версиями и включать их в свой проект; они не только облегчают разработку, но также могут быть использованы другими разработчиками и в производственной среде.
Подробную информацию о том, что может сделать утилита manage.py, см. в документации django-admin.
Использование 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 базы данных 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 admin по умолчанию активирован. Давайте запустим сервер разработки и посмотрим на него.
Если сервер не запущен, запустите его следующим образом:
$ python manage.py runserver
...\> py manage.py runserver
Теперь откройте веб-браузер и перейдите к «/admin/» на вашем локальном домене — например, http://127.0.0.1:8000/admin/. Вы должны увидеть экран входа в административную панель:
Поскольку перевод включён по умолчанию, если вы установите LANGUAGE_CODE, экран входа будет отображаться на заданном языке (если Django имеет соответствующие переводы).
Вход в административную панель
Теперь попробуйте войти в систему с учетной записью суперпользователя, которую вы создали на предыдущем шаге. Вы должны увидеть главную страницу административной панели Django:
Вы должны увидеть несколько типов редактируемого содержимого: группы и пользователей. Они предоставляются django.contrib.auth, фреймворком аутентификации, поставляемым Django.
Сделайте приложение опросов изменяемым в админ-панели
Но где наше приложение опросов? Оно не отображается на главной странице админ-панели.
Осталось только одно: необходимо сообщить админ-панели, что объекты Question имеют интерфейс администрирования. Для этого откройте файл polls/admin.py, и измените его так:
from django.contrib import admin from .models import Question admin.site.register(Question)
Изучите бесплатную функциональность админ-панели
Теперь, когда мы зарегистрировали Question, Django знает, что оно должно отображаться на главной странице админ-панели:
Question. DateTimeField, CharField) соответствуют соответствующему виджету HTML-ввода. Каждый тип поля знает, как отобразить себя в админке Django.DateTimeField получает бесплатные JavaScript-сокращения. Для дат есть сокращение «Сегодня» и всплывающее календарное окно, а для времени — сокращение «Сейчас» и удобное всплывающее окно, в котором перечислены часто вводимые временные значения.В нижней части страницы вам предлагается несколько вариантов:
- Сохранить — сохраняет изменения и возвращает на страницу со списком изменений для данного типа объекта.
- Сохранить и продолжить редактирование — сохраняет изменения и перезагружает страницу админки для данного объекта.
- Сохранить и добавить ещё — сохраняет изменения и загружает новую пустую форму для данного типа объекта.
- Удалить — отображает страницу подтверждения удаления.
Если значение «Дата публикации» не соответствует времени, когда вы создали вопрос в Уроке 1, это, вероятно, означает, что вы забыли установить правильное значение для параметра TIME_ZONE. Измените его, перезагрузите страницу и проверьте, что появляется правильное значение.
Измените «Дату публикации», нажав на сокращения «Сегодня» и «Сейчас». Затем нажмите «Сохранить и продолжить редактирование». Затем нажмите «История» в правом верхнем углу. Вы увидите страницу, на которой перечислены все изменения, внесённые в этот объект через админку Django, со временем и именем пользователя, который внес изменения:
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.0/intro/tutorial02/