Spec-Zone.ru › Django 5.0

Создание вашей первой 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 должен содержать полный абсолютный путь, включая имя файла, этого файла. Значение по умолчанию, 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. Question содержит вопрос и дату публикации. Choice имеет два поля: текст варианта ответа и счёт голосов. Каждый Choice связан с Question.

Эти концепции представлены классами Python. Отредактируйте файл polls/models.py, чтобы он выглядел так:

polls/models.py
from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField("date published")


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

Здесь каждая модель представлена классом, который наследуется от django.db.models.Model. Каждая модель имеет ряд переменных класса, каждая из которых представляет поле базы данных в модели.

Каждое поле представлено экземпляром класса Field — например, CharField для символьных полей и DateTimeField для дат и времени. Это говорит Django, какой тип данных содержит каждое поле.

Имя каждого экземпляра Field (например, question_text или pub_date) — имя поля в удобном для машины формате. Вы будете использовать это значение в своём коде Python, а ваша база данных будет использовать его в качестве имени столбца.

Можно использовать необязательный первый позиционный аргумент Field для обозначения удобочитаемого имени. Это используется в нескольких интроспективных частях Django и служит документацией. Если это поле не указано, Django будет использовать имя в удобном для машины формате. В данном примере мы определили только удобочитаемое имя для Question.pub_date. Для всех остальных полей в этой модели имя поля в удобном для машины формате будет достаточным в качестве удобочитаемого имени.

END_OF_DOCUMENT_MARKER

Некоторые классы 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. Он будет выглядеть так:

mysite/settings.py
INSTALLED_APPS = [
    "polls.apps.PollsConfig",
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]

Теперь Django знает, как включить приложение polls. Давайте выполним еще одну команду:

$ python manage.py makemigrations polls
...\> py manage.py makemigrations polls

Вы должны увидеть что-то похожее на следующее:

Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Question
    - Create model Choice

Выполняя makemigrations, вы сообщаете Django, что вы внесли некоторые изменения в свои модели (в данном случае вы создали новые) и хотите, чтобы эти изменения сохранились как миграция.

Миграции — это способ, которым Django сохраняет изменения в ваших моделях (а значит, и в схеме вашей базы данных) — это файлы на диске. Вы можете прочитать миграцию для вашей новой модели, если хотите; это файл polls/migrations/0001_initial.py. Не волнуйтесь, от вас не ожидается чтение их каждый раз, когда Django делает одну, но они предназначены для редактирования человеком в случае, если вы хотите вручную настроить, как 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" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    "question_text" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
    "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    "choice_text" varchar(200) NOT NULL,
    "votes" integer NOT NULL,
    "question_id" bigint 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), bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (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=datetime.timezone.utc)

# Change values by changing the attributes, then calling save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() displays all the questions in the database.
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>

Подождите минутку. <Question: Question object (1)> — не очень полезное представление об этом объекте. Давайте исправим это, отредактировав модель Question (в файле polls/models.py) и добавив метод __str__() в обе модели Question и Choice:

polls/models.py
from django.db import models


class Question(models.Model):
    # ...
    def __str__(self):
        return self.question_text


class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text

Важно добавлять методы __str__() в ваши модели не только для удобства при работе с интерактивным приглашением, но и потому, что представления объектов используются во всей автоматически сгенерированной административной панели Django.

Давайте также добавим пользовательский метод в эту модель:

polls/models.py
import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Обратите внимание на добавление import datetime и from django.utils import timezone для ссылки на стандартный модуль Python datetime и инструменты Django, связанные с часовыми поясами, в django.utils.timezone соответственно. Если вы не знакомы с обработкой часовых поясов в Python, вы можете узнать больше в документации по поддержке часовых поясов.

Сохраните эти изменения и запустите новую интерактивную оболочку 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/. Вы должны увидеть экран входа в систему администратора:

Django admin login screen

Поскольку перевод включен по умолчанию, если вы установите LANGUAGE_CODE, экран входа будет отображаться на заданном языке (если у Django есть соответствующие переводы).

Вход в систему администратора

Теперь попробуйте войти в систему с учетной записью суперпользователя, которую вы создали на предыдущем шаге. Вы должны увидеть главную страницу администратора Django:

Django admin index page

Вы должны увидеть несколько типов редактируемого контента: группы и пользователи. Они предоставляются django.contrib.auth, фреймворком аутентификации, поставляемым Django.

Сделать приложение опроса изменяемым в администраторе

Но где наше приложение опроса? Оно не отображается на главной странице администратора.

Осталось сделать только одно: необходимо сообщить администратору, что Question объекты имеют интерфейс администратора. Для этого откройте файл polls/admin.py и измените его следующим образом:

polls/admin.py
from django.contrib import admin

from .models import Question

admin.site.register(Question)

Исследуйте бесплатную функциональность администратора

Теперь, когда мы зарегистрировали Question, Django знает, что оно должно отображаться на главной странице администратора:

Django admin index page, now with polls displayed

Нажмите «Вопросы». Теперь вы находитесь на странице «список изменений» для вопросов. Эта страница отображает все вопросы в базе данных и позволяет выбрать один для изменения. Вот вопрос «Что происходит?», который мы создали ранее:

Polls change list page

Нажмите на вопрос «Что происходит?», чтобы отредактировать его:

Editing form for question object

Следует отметить следующее:

  • Форма автоматически генерируется из модели Question.
  • Разные типы полей модели (DateTimeField, CharField) соответствуют соответствующим виджетам входных данных HTML. Каждый тип поля знает, как отобразить себя в администраторе Django.
  • Каждый DateTimeField получает бесплатные сокращения JavaScript. Даты получают сокращение «Сегодня» и всплывающее окно календаря, а время получает сокращение «Сейчас» и удобное всплывающее окно, в котором перечислены часто вводимые временные отметки.

В нижней части страницы вы получите несколько вариантов:

  • Сохранить — сохраняет изменения и возвращает на страницу списка изменений для этого типа объекта.
  • Сохранить и продолжить редактирование — сохраняет изменения и перезагружает страницу администратора для этого объекта.
  • Сохранить и добавить другой — сохраняет изменения и загружает новую пустую форму для этого типа объекта.
  • Удалить — отображает страницу подтверждения удаления.

Если значение «Дата публикации» не соответствует времени, когда вы создали вопрос в Учебнике 1, это, вероятно, означает, что вы забыли установить правильное значение для параметра TIME_ZONE. Измените его, перезагрузите страницу и проверьте, что отображается правильное значение.

Измените «Дата публикации», нажав сокращения «Сегодня» и «Сейчас». Затем нажмите «Сохранить и продолжить редактирование». Затем нажмите «История» в правом верхнем углу. Вы увидите страницу, на которой перечислены все изменения, внесенные в этот объект с помощью администратора Django, с отметкой времени и именем пользователя, внесшего изменение:

History page for question object

Когда вы освоитесь с API моделей и ознакомитесь со сайтом администратора, прочитайте часть 3 этого учебника, чтобы узнать, как добавить дополнительные представления в наше приложение опроса.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.0/intro/tutorial02/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API