Как создавать модели Django

Вступление

В предыдущем учебном пособии «https://www.digitalocean.com/community/tutorials/how-to-create-a-django-app-and-connect-it-to-a-database[Как создать приложение Django и подключите его к базе данных] », мы рассмотрели, как создать базу данных MySQL, как создать и запустить приложение Django, и как подключить его к базе данных MySQL.

В этом руководстве мы создадим Djangomodels, которые определяют поля и поведение данных приложения блога, которые мы будем хранить. Эти модели отображают данные из вашего приложения Django в базу данных. Это то, что Django использует для генерации таблиц базы данных через API-интерфейс объектно-реляционного отображения (ORM), называемый «моделями».

Предпосылки

У вас должен быть установлен MySQL на сервере Ubuntu 16.04, а также у вас должно быть установлено соединение с базой данных с вашим приложением Django. Если вы этого еще не сделали, обратитесь к второй части серии Django: «https://www.digitalocean.com/community/tutorials/how-to-create-a-django-app-and-connect- it-to-a-database [Как создать приложение Django и подключить его к базе данных] ».

[[step-1 -—- create-django-application]] == Шаг 1. Создание приложения Django

Чтобы придерживаться философии модульности Django, мы создадим приложение Django в нашем проекте, которое будет содержать все файлы, необходимые для создания веб-сайта блога.

Сначала активируйте виртуальную среду Python:

cd ~/my_blog_app
. env/bin/activate
cd blog

Оттуда, давайте запустим эту команду:

python 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.

[[step-2 -—- add-the-posts-model]] == Шаг 2 - Добавьте модель сообщений

Сначала нам нужно открыть и отредактировать файл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.

models.py

from django.db import models

# Create your models here.

Используя свой любимый текстовый редактор или IDE, добавьте следующий код в файлmodels.py. Мы будем использоватьnano в качестве текстового редактора. Но вы можете использовать все, что вы предпочитаете.

nano models.py

В этом файле уже добавлен код для импорта API моделей, мы можем продолжить и удалить следующий комментарий. Затем мы импортируемslugify для генерации слагов из строк иUser Django для аутентификации следующим образом:

models.py

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.

models.py

...
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.py

...
@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 обычно содержит другую важную логику модели, не связанную с определением поля базы данных.

models.py

...
   class Meta:
        ordering = ['created_on']
        def __unicode__(self):
            return self.title

Наконец, мы добавим в этот файл модельComment. Это включает добавление другого класса с именемComment сmodels.Models в его сигнатуре и определением следующих полей базы данных:

  • name - Имя человека, публикующего комментарий.

  • email - адрес электронной почты человека, публикующего комментарий.

  • text - текст самого комментария.

  • post - сообщение, с которым был сделан комментарий.

  • created_on - время создания комментария.

models.py

...
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, on_delete=models.CASCADE)
    created_on = models.DateTimeField(auto_now_add=True)

Когда закончите, ваш полный файлmodels.py должен выглядеть так:

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, on_delete=models.CASCADE)
    created_on = models.DateTimeField(auto_now_add=True)

Обязательно сохраните и закройте файл.

Настроив файлmodels.py, мы можем продолжить обновление нашего файлаsettings.py.

[[step-3 -—- update-settings]] == Шаг 3 - Обновите настройки

Теперь, когда мы добавили модели в наше приложение, мы должны сообщить нашему проекту о существовании приложенияblogsite, которое мы только что добавили. Мы делаем это, добавляя его в разделINSTALLED_APPS вsettings.py.

Перейдите в каталог, в котором живет вашsettings.py.

cd ~/my_blog_app/blog/blog

Отсюда откройте ваш файлsettings.py, например, с помощью nano, используя командуnano settings.py.

Открыв файл, добавьте приложениеblogsite в раздел файлаINSTALLED_APPS, как показано ниже.

settings.py

# Application definition
INSTALLED_APPS = [
    'blogsite',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

С добавленным приложениемblogsite вы можете сохранить файл и выйти из него.

На данный момент мы готовы перейти к применению этих изменений.

[[step-4 -—- make-migrations]] == Шаг 4. Выполните миграцию

После добавления наших моделейPost иComment следующим шагом будет применение этих изменений, чтобы наша схема базы данныхMySQL распознала их и создала необходимые таблицы.

Давайте посмотрим, какие таблицы уже существуют в нашей базе данныхblog_data.

Для этого нам нужно войти на сервер MySQL.

[.note] #Note: В этом примере мы будем использовать имя пользователяroot без пароля, но вы должны использовать имя пользователя и пароль, которые вы установили для MySQL.
#

mysql blog_data -u root

Вы заметите, что если вы введете командуSHOW DATABASES;, то увидите следующее:

Output+--------------------+
| 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;
OutputEmpty set (0.00 sec)

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

Теперь мы приступим к миграции, которая применяет изменения, внесенные нами вmodels.py.

Закройте MySQL с помощьюCTRL +D.

Во-первых, мы должны упаковать изменения нашей модели в отдельные файлы миграции с помощью командыmakemigrations. Эти файлы похожи на файлыcommits в системе контроля версий, например,git.

Теперь, если вы перейдете к~/my_blog_app/blog/blogsite/migrations и запуститеls, вы заметите, что есть только файл__init__.py. Это изменится, как только мы добавим миграции.

Перейдите в каталог блога с помощьюcd, например:

cd ~/my_blog_app/blog
python manage.py makemigrations

Вы должны увидеть следующий вывод в окне терминала:

OutputMigrations 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? Если мы теперьcd вернулись в этот каталог, мы увидим, что были добавлены две вещи:__pycache__ и0001_initial.py. Файл0001_initial.py был автоматически создан при запускеmakemigrations. Подобный файл будет создаваться каждый раз, когда вы запускаетеmakemigrations.

Запуститеless 0001_initial.py, если хотите увидеть, что содержит файл.

Теперь перейдите к~/my_blog_app/blog.

Поскольку мы создали файл миграции, мы должны применить изменения, которые эти файлы описывают, к базе данных с помощью командыmigrate. Но сначала давайте посмотрим, какие существуют текущие миграции, с помощью командыshowmigrations.

python manage.py showmigrations
Outputadmin
 [ ] 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
 [ ] 0009_alter_user_last_name_max_length
blogsite
 [ ] 0001_initial
contenttypes
 [ ] 0001_initial
 [ ] 0002_remove_content_type_name
sessions
 [ ] 0001_initial

Вы заметите миграцию, которую мы только что добавили дляblogsite, которая содержит миграцию0001_initial для моделейPost иComment.

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

python 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.

python manage.py migrate

Мы увидим следующий вывод:

OutputOperations 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 auth.0009_alter_user_last_name_max_length... OK
  Applying blogsite.0001_initial... OK
  Applying sessions.0001_initial... OK

Вы успешно применили свои миграции.

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

  • Отсутствие поддержки транзакций вокруг операций изменения схемы. Другими словами, если миграция не может быть успешно применена, вам придется вручную отменить изменения, которые вы сделали, чтобы попытаться выполнить другую миграцию. Невозможно выполнить откат до более ранней точки, прежде чем были внесены какие-либо изменения в неудачной миграции.

  • Для большинства операций по изменению схемы MySQL полностью переписывает таблицы. В худшем случае сложность времени будет пропорциональна количеству строк в таблице для добавления или удаления столбцов. Согласно документации Django, это может быть медленным, как одна минута на миллион строк.

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

Для каждой базы данных, которую вы планируете использовать с Django, обязательно взвесите преимущества и недостатки каждой из них.

[[step-5 -—- verify-database-schema]] == Шаг 5 - Проверьте схему базы данных

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

Для этого выполните следующую команду в терминале, чтобы войти в MySQL.

mysql blog_data -u root

Теперь покажите базы данных, которые существуют.

SHOW DATABASES;

Выбираем нашу базу данныхblog_data:

USE blog_data;

Затем введите следующую команду, чтобы просмотреть таблицы.

SHOW TABLES;

Вы должны увидеть следующее:

Output+----------------------------+
| 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;
Output+------------+--------------+------+-----+---------+----------------+
| 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;
Output+------------+--------------+------+-----+---------+----------------+
| 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.

Вы можете закрыть MySQL с помощьюCTRL +D, и когда вы будете готовы покинуть среду Python, вы можете запустить командуdeactivate:

deactivate

Деактивация среды программирования вернет вас в командную строку терминала.

Заключение

В этом руководстве мы успешно добавили модели для основных функций в веб-приложение блога. Вы узнали, как кодироватьmodels, как работаетmigrations и как преобразовывать Djangomodels в реальные таблицы базы данныхMySQL.

Related