В предыдущем руководстве (Создание приложения Django и подключение к базе данных) вы научились создавать БД MySQL и приложения Django, а также настраивать их взаимодействие.
Данное руководство научит создавать модели Django, которые определяют поля и поведение данных приложения. Эти модели отображают данные приложения Django в БД. Django использует модели для генерации таблиц базы данных через API объектного-реляционного отображения данных (ORM).
Требования
- Сервер Ubuntu 16.04.
- Установленная система MySQL.
- Приложение Django, которое взаимодействует с БД MySQL.
Все необходимые инструкции вы найдете в руководстве Создание приложения Django и подключение к базе данных.
1: Создание приложения Django
Согласно философии модульности Django создайте в проекте Django-приложение, которое содержит все файлы, необходимые для создания блога.
Откройте каталог:
cd ~/my_blog_app/blog
Запустите команду:
python3 manage.py startapp blogsite
В каталоге появится такая структура каталогов:
my_blog_app/
└── blog
├── blog
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-35.pyc
│ │ ├── settings.cpython-35.pyc
│ │ ├── urls.cpython-35.pyc
│ │ └── wsgi.cpython-35.pyc
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── blogsite
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py
В данном руководстве сосредоточим внимание на файле models.py.
2: Создание модели Post
Сначала нужно открыть и отредактировать файл models.py и добавить в него код для создания модели Post. Модель Post содержит следующие поля базы данных:
- title – заголовок публикации.
- slug – валидные URL-адреса, которые хранятся и генерируются для веб-страниц.
- content – текст публикации/ заметки.
- created_on – дата создания заметки.
- author – автор этой публикации.
Перейдите в каталог, в котором хранится models.py:
cd ~/my_blog_app/blog/blogsite
С помощью команды cat выведите содержимое файла в терминал:
cat models.py
Файл должен содержать следующий код, который импортирует модели, а также комментарий, описывающий, что нужно поместить в этот файл models.py.
from django.db import models
# Create your models here.
С помощью текстового редактора добавьте в файл следующий код.
nano models.py
В файле уже есть код для импорта API-интерфейсов моделей, вы можете удалить комментарий. Затем импортируйте slugify для создания слагов из строк, и User для аутентификации:
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
Затем добавьте в класс моделей класс метода Post с перечисленными полями БД (title, slug, content, created_on и author).
...
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.TextField()
Затем добавьте функции для генерации URL-адреса и функции сохранения постов. Это создаст уникальную ссылку, соответствующую каждому уникальному сообщению.
...
@models.permalink
def get_absolute_url(self):
return ('blog_post_detail', (),
{
'slug': self.slug,
})
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
Теперь нужно указать, как модель должна упорядочивать посты и отображать их на веб-странице. Эта логика будет добавлена во встроенный внутренний класс Meta. Класс Meta обычно содержит важную логику модели, которая не связана с определением поля базы данных.
...
class Meta:
ordering = ['created_on']
def __unicode__(self):
return self.title
Добавьте в файл модель Comment. Для этого добавьте новый класс Comment с models.Models и следующими полями базы данных:
- name – имя пользователя, который публикует комментарий.
- email – адрес электронной почты пользователя, который публикует комментарий.
- text – текст комментария.
- post – запись, к которой относится комментарий.
- created_on – время создания комментария.
…
class Comment(models.Model):
name = models.CharField(max_length=42)
email = models.EmailField(max_length=75)
website = models.URLField(max_length=200, null=True, blank=True)
content = models.TextField()
post = models.ForeignKey(Post)
created_on = models.DateTimeField(auto_now_add=True)
В результате файл models.py должен выглядеть так:
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.TextField()
@models.permalink
def get_absolute_url(self):
return ('blog_post_detail', (),
{
'slug': self.slug,
})
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
class Meta:
ordering = ['created_on']
def __unicode__(self):
return self.title
class Comment(models.Model):
name = models.CharField(max_length=42)
email = models.EmailField(max_length=75)
website = models.URLField(max_length=200, null=True, blank=True)
content = models.TextField()
post = models.ForeignKey(Post)
created_on = models.DateTimeField(auto_now_add=True)
Сохраните и закройте файл.
Теперь нужно откорректировать файл settings.py.
3: Обновление параметров
Создав модели для приложения, нужно сообщить проекту о существовании приложения blogsite. Для этого добавьте приложение в раздел INSTALLED_APPS в файле settings.py.
Откройте каталог, в котором хранится settings.py:
cd ~/my_blog_app/blog/blog
Затем откройте этот файл:
nano settings.py
Открыв файл, добавьте blogsite в раздел INSTALLED_APPS, как показано ниже.
# Application definition
INSTALLED_APPS = [
'blogsite',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Сохраните и закройте файл.
4: Миграция
Создав модели Post и Comment, нужно активировать изменения, чтобы схема БД MySQL могла их распознавать и создавать необходимые таблицы.
Для этого нам нужно войти на сервер MySQL.
Примечание: В этом примере используется аккаунт root без пароля, но вы должны использовать имя пользователя и пароль, которые вы настроили для MySQL.
mysql -u root
Введите команду SHOW DATABASES; и вы увидите:
+--------------------+
| Database |
+--------------------+
| information_schema |
| blog_data |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
Откройте БД blog_data и запросите ее таблицы (если такие есть).
USE blog_data;
Чтобы просмотреть таблицы в БД blog_data, введите:
SHOW TABLES;
+---------------------+
| Tables_in_blog_data |
+---------------------+
| django_migrations |
+---------------------+
Эта таблица django_migrations, которую вы видите в выводе, сообщает системе миграции Django текущее состояние базы данных, благодаря чему БД знает, какие миграции необходимо выполнить.
Теперь нужно активировать изменения, внесенные в models.py.
Закройте MySQL (CTRL + D).
Сначала изменения моделей нужно спакетировать в индивидуальные файлы с помощью makemigrations (эти файлы похожи на коммиты в git).
Перейдите в ~/my_blog_app/blog/blogsite/migrations и запустите ls. Вы увидите только файл __init__.py. После миграции файлов станет больше.
Откройте этот каталог:
cd ~/my_blog_app/blog
python3 manage.py makemigrations
В окне терминала появится такой вывод:
Migrations for 'blogsite':
blogsite/migrations/0001_initial.py
- Create model Comment
- Create model Post
- Add field post to comment
Если теперь вернуться к каталогу /~/my_blog_app/blog/blogsite/migrations (в котором еще недавно был только файл __init__.py), вы увидите в нем два новых файла – __pycache__ и 0001_initial.py. Файл 0001_initial.py был сгенерирован автоматически во время запуска makemigrations. Подобный файл генерируется во время каждого запуска makemigrations.
Если вы хотите просмотреть содержимое этого файла, введите:
less 0001_initial.py
Теперь перейдите в /~/my_blog_app/blog.
Поскольку вы создали файл миграции, вы должны применить изменения, которые содержат эти файлы, с помощью команды migrate. Но сначала просмотрите текущие миграции, используя команду showmigrations.
python3 manage.py showmigrations
admin
[ ] 0001_initial
[ ] 0002_logentry_remove_auto_add
auth
[ ] 0001_initial
[ ] 0002_alter_permission_name_max_length
[ ] 0003_alter_user_email_max_length
[ ] 0004_alter_user_username_opts
[ ] 0005_alter_user_last_login_null
[ ] 0006_require_contenttypes_0002
[ ] 0007_alter_validators_add_error_messages
[ ] 0008_alter_user_username_max_length
blogsite
[ ] 0001_initial
contenttypes
[ ] 0001_initial
[ ] 0002_remove_content_type_name
sessions
[ ] 0001_initial
Вы увидите миграцию для blogsite, которая содержит миграцию 0001_initial моделей Post и Comment.
Теперь просмотрите инструкции SQL, которые будут выполняться после миграций. В качестве аргумента команды укажите название миграции:
python3 manage.py sqlmigrate blogsite 0001_initial
Вы увидите SQL-запрос:
BEGIN;
--
-- Create model Comment
--
CREATE TABLE `blogsite_comment` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(42) NOT NULL, `email` varchar(75) NOT NULL, `website` varchar(200) NULL, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL);
--
-- Create model Post
--
CREATE TABLE `blogsite_post` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `title` varchar(255) NOT NULL, `slug` varchar(255) NOT NULL UNIQUE, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL, `author` longtext NOT NULL);
--
-- Add field post to comment
--
ALTER TABLE `blogsite_comment` ADD COLUMN `post_id` integer NOT NULL;
ALTER TABLE `blogsite_comment` ADD CONSTRAINT `blogsite_comment_post_id_de248bfe_fk_blogsite_post_id` FOREIGN KEY (`post_id`) REFERENCES `blogsite_post` (`id`);
COMMIT;
Теперь нужно выполнить миграцию, чтобы применить изменения в БД MySQL:
python3 manage.py migrate
Команда выведет:
Operations to perform:
Apply all migrations: admin, auth, blogsite, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying blogsite.0001_initial... OK
Applying sessions.0001_initial... OK
Миграция успешно выполнена.
Важно иметь в виду, что в миграции Django и MySQL есть 3 нюанса (согласно документации Django).
- Нет поддержки транзакций в операциях изменения схемы. Другими словами, если миграция не сможет пройти успешно, вам придется вручную вводить изменения, чтобы попытаться выполнить другую миграцию. Откат до более ранней точки невозможен до внесения каких-либо изменений в неудачную миграцию.
- В большинстве операций по изменению схемы MySQL полностью перепишет таблицы. В худшем случае задержка пропорциональна количеству строк в таблице. Согласно документации Django, на это уходит одна минута на миллион строк.
- В MySQL существуют небольшие ограничения на длину имен для столбцов, таблиц и индексов. Лимиты зависят от сервера бэкэнда. Хотя некоторые другие серверы могут поддерживать более высокие лимиты, созданные в Django, бэкэнд MySQL не сможет создать такие же индексы.
Обязательно оцените преимущества и недостатки каждой базы данных, которую вы собираетесь использовать с Django.
5: Проверка схемы базы данных
После завершения миграции нужно проверить таблицы MySQL, которые были созданы с помощью моделей Django.
Для этого войдите в MySQL:
mysql -u root
Запросите список баз данных:
SHOW DATABASES;
Выберите БД blog_data:
USE blog_data;
Запросите список таблиц:
SHOW TABLES;
+----------------------------+
| Tables_in_blog_data |
+----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| blogsite_comment |
| blogsite_post |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+----------------------------+
В БД появились таблицы blogsite_comment и blogsite_post. Это модели, которые вы разработали ранее. Убедитесь, что они содержат необходимые поля:
DESCRIBE blogsite_comment;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(42) | NO | | NULL | |
| email | varchar(75) | NO | | NULL | |
| website | varchar(200) | YES | | NULL | |
| content | longtext | NO | | NULL | |
| created_on | datetime(6) | NO | | NULL | |
| post_id | int(11) | NO | MUL | NULL | |
+------------+--------------+------+-----+---------+----------------+
7 rows in set (0.01 sec)
DESCRIBE blogsite_post;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| slug | varchar(255) | NO | UNI | NULL | |
| content | longtext | NO | | NULL | |
| created_on | datetime(6) | NO | | NULL | |
| author | longtext | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)
Таблицы базы данных были успешно сгенерированы на основе моделей Django.
Заключение
В этом руководстве вы научились добавлять модели для базовой функциональности блога. Теперь вы знаете, как писать код моделей, как работают миграции и процесс перевода моделей Django в таблицы базы данных MySQL.