1-8. モデルの作成

今回のテーマは「モデルの作成」です。ここまで非常に初歩ですが、ViewとTemplateについて見てきました。残りはModelですね。Djangoではモデルに様々な情報をもたせることでデータベースとの連携やバリデーション処理をスマートに行える仕組みを持っています。今回は掲示板ということで簡単なモデルを作って学習することにしましょう。

※本ページはTemplateViewでテンプレートを表示するまで読まれた方を対象としています。そのためサンプルソースコードが省略されている場合があります。


threadアプリケーションの追加

まずはthreadアプリケーションを作ります。これは掲示板のスレッドに関することを処理するアプリケーションです。


(venv)$ ./manage startapp thread

baseアプリケーションと同様にthread/urls.pyの追加、mysite/settings.pyにアプリケーションの追加、mysite/urls.pyにURLの追加を行います。この辺りはbaseアプリケーションと同様です。

mysite/settings.py(一部抜粋)


  INSTALLED_APPS = [
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
      'django.contrib.sites',
      'django.contrib.sitemaps',
      'debug_toolbar',
      'base',
+     'thread',
  ]

mysite/urls.py(一部抜粋)


  urlpatterns = [
      path('admin/', admin.site.urls),
      path('accounts/', include('django.contrib.auth.urls')),
      path('accounts/', include('accounts.urls')),
      path('', include('base.urls')),
+     path('thread/', include('thread.urls')),
  ]

thread/urls.py


from django.urls import path

from . import views
app_name = 'thread'

urlpatterns = [
]

これでアプリケーションの追加処理はOKです。

モデルの追加

threadアプリケーションのモデルは以下の様なものを想定します。まずは掲示板の最低限の機能を有するように以下のようなモデルを考えます。

Topic: ID、タイトル、本文、ユーザー名、作成日、更新日
Comment: ID、本文、ユーザー、作成日、公開フラグ
Category: ID、タイトル、ソート番号、URLコード

まずはソース全体がどうなるかを見てみましょう。thread/models.pyは以下のようになります。
thread/models.py


from django.db import models
from django.contrib.auth.models import User

class TopicManager(models.Manager):
    # Topic操作に関する処理を追加
    pass

class CommentManager(models.Manager):
    # Comment操作に関する処理を追加
    pass

class CategoryManager(models.Manager):
    # Category操作に関する処理を追加
    pass

class Category(models.Model):
    name = models.CharField(
        'カテゴリー名',
        max_length=50,
    )
    url_code = models.CharField(
        'URLコード',
        max_length=50,
        null=True,
        blank=False,
        unique=True,
    )
    sort=models.IntegerField(
        verbose_name='ソート',
        default=0,
    )
    objects = CategoryManager

    def __str__(self):
        return self.name

class Topic(models.Model):
    user_name = models.CharField(
        'お名前',
        max_length=30,
        null=True,
        blank=False,
    )
    title = models.CharField(
        'タイトル',
        max_length=255,
        null = False,
        blank = False,
    )
    message = models.TextField(
        verbose_name='本文',
        null=True,
        blank=False,
    )
    category = models.ForeignKey(
        Category,
        verbose_name='カテゴリー',
        on_delete=models.PROTECT,
        null=True,
        blank=False,
    )
    created = models.DateTimeField(
        auto_now_add=True,
    )
    modified = models.DateTimeField(
        auto_now=True,
    )
    objects = TopicManager()

    def __str__(self):
        return self.title

class Comment(models.Model):
    id = models.BigAutoField(
        primary_key=True,
    )
    no = models.IntegerField(
        default=0,
    )
    user_name = models.CharField(
        'お名前',
        max_length=30,
        null=True,
        blank=False,
    )
    topic = models.ForeignKey(
        Topic,
        on_delete=models.PROTECT,
    )
    message = models.TextField(
        verbose_name='投稿内容'
    )
    pub_flg = models.BooleanField(
        default=True,
    )
    created = models.DateTimeField(
        auto_now_add=True,
    )
    objects = CommentManager()

    def __str__(self):
        return '{}-{}'.format(self.topic.id, self.no)

簡単な解説

モデルフィールド

モデルの各クラスのプロパティはモデルフィールドで規定していきます。公式のモデルフィールドリファレンスにモデルフィールドの種類がまとまっています。Djangoではモデルが持つ関連情報はできるだけ一箇所にまとめることを理想としていて、データベース格納時のデータ型、リレーションに関する情報、デフォルト値、nullの許容等の情報を付与していきます。多くのWeb開発ではAPIの設計、データベース設計を終えた後に実装に入ると思いますので、設計を素直にモデルに書き起こしていく作業となります。

nullとblank

nullとblankが出てきました。nullはデータベース上でNULLを許容するかどうか?であり、blankはユーザーが入力項目として必須項目にするかどうかということです。具体的にはblankにFalseを当てるとフォームでインプットタグにrequiredが付きます。

IDの自動生成

さて、IDに関する記述がないのに気づきましたか?IDに関しては明記しない場合はDjangoによって自動生成されます。その場合はデータ型はintとなりPrimary Keyが設定されます。

外部キー

今回、1対多の関係を構築するためにトピックはカテゴリーのidをコメントはトピックのidを保有しています。このような場合DjangoではForeignKeyを用います。その場合、外部キーとして保有してるモデルが削除された場合の削除方法をon_deleteで指定します。種類としては以下のようなものがあります。

models.CASCADE : 外部キーのモデルと一緒に参照しているモデルも削除される
models.PROTECT : 保護される(参照されている場合には削除できない)
models.SET_NULL : 外部キーのモデルが削除された場合IDはNULLとなる
models.SET_DEFAULT : デフォルトで設定されている値がセットされる。

オススメはPROTECTでしょうか。CASCADEは少々リスクが高いですが、設計次第では問題ないと思います。

マネージャーについて

また、今回はTopicManagerとCommentManager,CategoryManagerを用意し、各モデルのobjectsと紐づけました。今後、各モデルに関する操作に関わる処理はこのマネージャーに追加していき、ビューからはその処理を呼び出し、モデルに作用するようにします。慣れない内はViewで多くの処理をしてしまい肥大化しがちですが、モデルが担うビジネスロジックの処理はモデルで行うべきかと(自戒をこめて)考えています。

Django標準のUserクラスについて

今回はDjango標準のUserクラスを使用しましたが、AbstructBaseUserやBaseUserManagerをオーバライドすることでカスタムユーザーを作ることも可能です。(ただし、これは初回のマイグレーションより前に作成する必要があります。)これについては後々詳しく扱えればと思います。

最後に

解説が駆け足となってしまい、説明が不十分な点もあるかと思いますが、まずはDjangoのモデルがどういう性質のものかを体感してもらうことが大事かと思います。次回は作成したモデルを使っていきますよ。

Sponsored Link


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です