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は、「モデル」と呼ばれるオブジェクトリレーショナルマッピング(ORM)APIを介してデータベーステーブルを生成するために使用します。

前提条件

MySQLをUbuntu 16.04サーバーにインストールし、Djangoアプリケーションとデータベース接続をセットアップする必要があります。 まだこれを行っていない場合は、Djangoシリーズのパート2、「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哲学を維持するために、ブログWebサイトの作成に必要なすべてのファイルを含む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—投稿モデルを追加する

まず、Postモデルを生成するためのコードが含まれるように、models.pyファイルを開いて編集する必要があります。 Postモデルには、次のデータベースフィールドが含まれています。

  • title —ブログ投稿のタイトル。

  • slug —Webページの有効な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をインポートし、次のように認証のためにDjangoのUserをインポートします。

models.py

from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User

次に、Postを呼び出すモデルクラスに、次のデータベースフィールド、titleslugcontentcreated_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)

次に、投稿がどのように順序付けられ、Webページに表示されるかをモデルに伝える必要があります。 このためのロジックは、ネストされた内部Metaクラスに追加されます。 Metaクラスには通常、データベースフィールドの定義に関係のない他の重要なモデルロジックが含まれています。

models.py

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

最後に、Commentモデルをこのファイルに追加します。 これには、署名にmodels.Modelsが含まれ、次のデータベースフィールドが定義されているCommentという名前の別のクラスを追加することが含まれます。

  • 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アプリの存在をプロジェクトに通知する必要があります。 これを行うには、settings.pyINSTALLED_APPSセクションに追加します。

settings.pyが存在するディレクトリに移動します。

cd ~/my_blog_app/blog/blog

ここから、コマンドnano settings.pyを使用して、たとえば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—移行を行う

モデルPostCommentを追加したら、次のステップはこれらの変更を適用して、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で行った変更を適用する移行を行います。

CTRL +DでMySQLを閉じます。

まず、コマンドmakemigrationsを使用して、モデルの変更を個々の移行ファイルにパッケージ化する必要があります。 これらのファイルは、gitのようなバージョン管理システムのcommitsのファイルに似ています。

ここで、~/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の2つが追加されていることがわかります。 makemigrationsを実行すると、0001_initial.pyファイルが自動的に生成されました。 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に追加した移行に気付くでしょう。これには、モデルPostCommentの移行0001_initialが含まれています。

次のコマンドを使用して、移行を行った後に実行される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の移行には3つの注意事項があることに留意することが重要です。

  • スキーマ変更操作に関するトランザクションのサポートの欠如。 つまり、移行が正常に適用されない場合、別の移行を試行するには、行った変更を手動で選択解除する必要があります。 失敗した移行で変更が行われる前に、以前の時点にロールバックすることはできません。

  • ほとんどのスキーマ変更操作では、MySQLはテーブルを完全に書き換えます。 最悪の場合、時間の複雑さは、列を追加または削除するテーブルの行数に比例します。 Djangoのドキュメントによると、これは100万行につき1分程度の遅い可能性があります。

  • MySQLでは、列、テーブル、インデックスの名前の長さに小さな制限があります。 また、すべての列とインデックスカバーの合計サイズにも制限があります。 他の一部のバックエンドはDjangoで作成されたより高い制限をサポートできますが、MySQLバックエンドを適切に配置すると同じインデックスを作成できません。

Djangoでの使用を検討している各データベースについて、それぞれの長所と短所を必ず検討してください。

[[step-5 -—- verify-database-schema]] ==ステップ5—データベーススキーマを確認する

移行が完了したら、Djangoモデルを介して作成したMySQLテーブルが正常に生成されたことを確認する必要があります。

これを行うには、ターミナルで次のコマンドを実行して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_commentblogsite_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モデルの移行からデータベーステーブルが正常に生成されたことを確認しました。

CTRL +Dを使用してMySQLを終了でき、Python環境を終了する準備ができたら、deactivateコマンドを実行できます。

deactivate

プログラミング環境を非アクティブ化すると、ターミナルコマンドプロンプトに戻ります。

結論

このチュートリアルでは、ブログWebアプリケーションの基本機能のモデルを正常に追加しました。 modelsをコーディングする方法、migrationsがどのように機能するか、Djangomodelsを実際のMySQLデータベーステーブルに変換するプロセスを学習しました。

Related