Создание моделей в Django

В предыдущем руководстве (Создание приложения 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).

  1. Нет поддержки транзакций в операциях изменения схемы. Другими словами, если миграция не сможет пройти успешно, вам придется вручную вводить изменения, чтобы попытаться выполнить другую миграцию. Откат до более ранней точки невозможен до внесения каких-либо изменений в неудачную миграцию.
  2. В большинстве операций по изменению схемы MySQL полностью перепишет таблицы. В худшем случае задержка пропорциональна количеству строк в таблице. Согласно документации Django, на это уходит одна минута на миллион строк.
  3. В 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.

Tags: , ,