Djangoモデルを作成する方法

提供:Dev Guides
移動先:案内検索

序章

前のチュートリアル「Djangoアプリを作成してデータベースに接続する方法」では、MySQLデータベースを作成する方法、Djangoアプリケーションを作成して起動する方法、およびデータベースに接続する方法について説明しました。 MySQLデータベース。

このチュートリアルでは、保存するブログアプリケーションデータのフィールドと動作を定義するDjangoモデルを作成します。 これらのモデルは、Djangoアプリケーションからのデータをデータベースにマップします。 これは、Djangoが「モデル」と呼ばれるオブジェクトリレーショナルマッピング(ORM)APIを介してデータベーステーブルを生成するために使用するものです。

前提条件

このチュートリアルはDjango開発シリーズの一部であり、そのシリーズの続きです。

このシリーズに従わなかった場合は、次のことを前提としています。

  • Djangoバージョン3以降がインストールされています。
  • Djangoアプリをデータベースに接続しました。 MySQLを使用しています。この接続は、Djangoシリーズのパート2「Djangoアプリを作成してデータベースに接続する方法」に従うことで実現できます。
  • Unixベースのオペレーティングシステム、できればUbuntu 20.04クラウドサーバーを使用しています。これは、私たちがテストしたシステムです。 同様の環境でDjangoをセットアップする場合は、チュートリアル「 Ubuntu20.04にDjangoをインストールして開発環境をセットアップする方法」を参照してください。

このチュートリアルは主にDjangoモデルを扱っているため、セットアップが多少異なっていても従うことができる場合があります。

ステップ1—Djangoアプリケーションを作成する

モジュール性のDjango哲学と一致するように、ブログWebサイトの作成に必要なすべてのファイルを含むDjangoアプリをプロジェクト内に作成します。

PythonとDjangoで作業を開始するときはいつでも、Python仮想環境をアクティブにして、アプリのルートディレクトリに移動する必要があります。 シリーズをフォローしている場合は、次のように入力することでこれを実現できます。

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

そこから、次のコマンドを実行してみましょう。

python manage.py startapp blogsite

これにより、blogsiteディレクトリとともにアプリが作成されます。

チュートリアルシリーズのこの時点で、プロジェクトのディレクトリ構造は次のようになります。

my_blog_app/
└── blog
    ├── blog
    │   ├── __init__.py
    │   ├── __pycache__
    │   │   ├── __init__.cpython-38.pyc
    │   │   ├── settings.cpython-38.pyc
    │   │   ├── urls.cpython-38.pyc
    │   │   └── wsgi.cpython-38.pyc
    │   ├── asgi.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── blogsite
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    └── manage.py

このチュートリアルで焦点を当てるファイルは、blogsiteディレクトリにあるmodels.pyファイルです。

ステップ2—投稿モデルを追加する

まず、models.pyファイルを開いて編集し、Postモデルを生成するためのコードが含まれるようにする必要があります。 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.

お気に入りのテキストエディタを使用して、models.pyファイルに次のコードを追加します。 テキストエディタとしてnanoを使用しますが、お好きなものを使用できます。

nano models.py

このファイル内に、モデルAPIをインポートするためのコードがすでに追加されています。先に進んで、次のコメントを削除できます。 次に、文字列からスラッグを生成するためのslugify、認証用のDjangoのUserdjango.urlsからのreverseをインポートして、URL作成の柔軟性を高めます。

models.py

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

次に、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

...
    def get_absolute_url(self):
        return reverse('blog_post_detail', args=[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モデルをこのファイルに追加します。 これには、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ファイルが以下と一致することを確認してください。

models.py

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


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()

    def get_absolute_url(self):
        return reverse('blog_post_detail', args=[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)

必ずファイルを保存して閉じてください。 nanoを使用している場合は、CTRLXYENTERの順に入力します。

models.pyファイルを設定したら、settings.pyファイルの更新に進むことができます。

ステップ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アプリを追加すると、ファイルを保存して終了できます。

この時点で、これらの変更を適用する準備が整いました。

ステップ4—移行を行う

モデルPostCommentを追加したら、次のステップはこれらの変更を適用して、MySQLデータベーススキーマがそれらを認識し、必要なテーブルを作成するようにします。

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

ここで、~/my_blog_app/blog/blogsite/migrationsに移動してlsを実行すると、__init__.pyファイルしかないことに気付くでしょう。 移行を追加すると、これは変更されます。

次のように、cdを使用してブログディレクトリに移動します。

cd ~/my_blog_app/blog

次に、manage.pymakemigrationsコマンドを実行します。

python manage.py makemigrations

次に、ターミナルウィンドウに次の出力が表示されます。

OutputMigrations for 'blogsite':
  blogsite/migrations/0001_initial.py
    - Create model Post
    - Create model 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に移動します。

cd ~/my_blog_app/blog

移行ファイルを作成したので、コマンドmigrateを使用して、これらのファイルに記述されている変更をデータベースに適用する必要があります。 ただし、最初にshowmigrationsコマンドを使用して、現在どの移行が存在するかを確認しましょう。

python manage.py showmigrations
Outputadmin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
 [X] 0010_alter_group_name_max_length
 [X] 0011_update_proxy_permissions
blogsite
 [ ] 0001_initial
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
sessions
 [X] 0001_initial

モデルPostおよびCommentで作成した0001_initialの移行を除いて、すべての移行がチェックされていることがわかります。

次に、次のコマンドを使用して、移行後にどのSQLステートメントが実行されるかを確認しましょう。 引数として移行と移行のタイトルを取ります。

python manage.py sqlmigrate blogsite 0001_initial

以下に示すのは、舞台裏で行われている実際のSQLクエリです。

Output--
-- 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);
--
-- 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, `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`);

次に、MySQLデータベースに適用されるように移行を実行してみましょう。

python manage.py migrate

次の出力を受け取ります。

OutputOperations to perform:
  Apply all migrations: admin, auth, blogsite, contenttypes, sessions
Running migrations:
  Applying blogsite.0001_initial... OK

これで、移行が正常に適用されました。

Djangoのドキュメントに記載されているように、バックエンドとしてMySQLを使用したDjangoの移行には3つの注意点があることに注意してください。

  • スキーマ変更操作に関するトランザクションのサポートの欠如。 つまり、移行が正常に適用されない場合は、別の移行を試みるために、行った変更を手動で選択解除する必要があります。 失敗した移行に変更が加えられる前に、以前の時点にロールバックすることはできません。
  • ほとんどのスキーマ変更操作では、MySQLはテーブルを完全に書き換えます。 最悪の場合、時間計算量は、列を追加または削除するテーブルの行数に比例します。 Djangoのドキュメントによると、これは100万行あたり1分ほど遅くなる可能性があります。
  • MySQLでは、列、テーブル、およびインデックスの名前の長さに小さな制限があります。 すべての列とインデックスカバーの合計サイズにも制限があります。 他のいくつかのバックエンドはDjangoで作成されたより高い制限をサポートできますが、MySQLバックエンドを配置すると同じインデックスを作成できません。

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

ステップ5—データベーススキーマを確認する

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

これを行うには、ターミナルで次のコマンドを実行してMySQLにログインします。 前のチュートリアルで作成したdjangouserを使用します。

mysql blog_data -u djangouser

次に、データベースblog_dataを選択します。 使用しているデータベースがわからない場合は、SQLでSHOW DATABASES;を使用してすべてのデータベースを表示できます。

USE blog_data;

次に、次のコマンドを入力してテーブルを表示します。

SHOW TABLES;

このSQLクエリは、次のことを明らかにするはずです。

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             |
+----------------------------+
12 rows in set (0.01 sec)

テーブルの中にはblogsite_commentblogsite_postがあります。 これらは私たちが自分たちで作ったばかりのモデルです。 定義したフィールドが含まれていることを検証しましょう。

DESCRIBE blogsite_comment;
Output+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int          | 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          | NO   | MUL | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)
DESCRIBE blogsite_post;
Output+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int          | 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.00 sec)

Djangoモデルの移行からデータベーステーブルが正常に生成されたことを確認しました。

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

deactivate

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

結論

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