Django: DBを扱うmodelsについて

この記事の内容
  • DjangoのModelについて
  • models.pyについて

この記事の対象者
  • Web開発に興味を持っている方
  • Djangoの学習者
  • Pythonエンジニア

この記事の構成
  1. Modelsの立ち位置
  2. テーブルの作成
  3. フィールドの追加

この記事では少しだけDjango開発について理解をしているという前提でお話をしていきます。

以下のスキルセットは、既に習得している前提です。

  • virtualenvで仮想環境の構築ができる
  • pip install でdjangoなどのライブラリのインストールができる
  • django-admin startproject で プロジェクトを立ち上げることができる
  • python manage.py startapp でアプリケーションをプロジェクトに追加することができる

1. Modelsの立ち位置

今回は、モデルを理解していくために、 models.py に記述するDBのテーブルのフィールドの内容などを見ていきます。

アプリケーションをプロジェクトに追加(startapp)すると、views.py と models.py、その他のファイルがプロジェクトに追加されます。


blog という アプリケーションを追加すると、プロジェクトに blogというディレクトリが追加されます。
blogディレクトリの中には、

  • admin.py
  • app.py
  • models.py
  • tests.py
  • views.py

が自動的に追加されています。

このblogというアプリケーションにおいて、DBの設計を models.py で行なっていきます。

2. テーブルの作成

まずは、テーブルを作成する方法について、学習していきます。

下記の要件のテーブルを作るとします。

article

  • 記事名(title)
  • イメージ写真(image)
  • 本文(body)
  • 投稿者(creator)
  • 更新者(modifier)
  • 投稿日(created)
  • 更新日(modified)

以下のように記述することで、テーブルを作成することができます。

class Article(models.Model):
    title = models.CharField()
    image = models.ImageField()
    body = models.TextField()
    creator = models.CharField()
    modifier = models.CharField()
    created = models.DateTimeField()
    modified = models.DateTimeField()

上記にある models は django.db というところから、dbのコードをimportしています。(下記のように、初めから書かれています。)

from django.db import models

テーブルの作成はこれだけでできます!!
なお、id(primary key/pk)については、何も記述しなければ、Djangoが自動で作成してくれるので、わざわざ毎回、記述必要する必要はありません。
素晴らしいですね :)

そして、さらにテーブルを色々カスタマイズしていくことも可能です。
例えば、articleテーブルを、別のテーブルから参照したい場合、
本来は、自動で作成されるテーブルのIDが表示されます。

<Instance "table" 1>

上記のような形だと非常に見づらいので、記事の名前を返すようにできるとわかりやすくなると思います。

そのような仕様を入れる場合、classの最後に以下のようなコードを追加します。

class Article(***):
    title = models.CharField()
    ****
    ****

    def __str__(self):
        return self.title

上記のように書くことで、特定のArticleテーブルを参照した時、記事のタイトルが返るようになります。

3. フィールドの追加

実際に、テーブルを書くためには、フィールドの知識が必要になって来ます。

よく使うフィールドをここでは覚えておきましょう!

  • CharField (文字列が入る)
  • TextField(文章が入る)
  • ImageField(写真ファイルが入る)
  • FileField(不特定のファイルが入る)
  • IntegerField(数値が入る)
  • BooleanField(True/False)が入る *いわゆるフラッグ
  • DateField(日付が入る)
  • DateTimeField(日時が入る)
  • ForeignKey(外部キー) *一対多のリレーションになる。(言葉だけでも覚えておきましょう!)
  • ManyToManyField(複数の外部キーが入る) *多対多のリレーションになる
  • OneToOneField(外部キー) *一対一のリレーションになる

一つずつ見ていきましょう!!

CharField

主に、文字が入ります。(改行はできません。)

注意点

  • 文字数制限をかけないといけない
    • max_length = 255 などで、数字を明示的に指定します。

TextField

主に、文章が入ります。(改行が可能。)
- 文字数制限をかけることもできます。(マストではない。)

豆知識

  • 外部ライブラリなどを使うことで、リッチテキストや、マークダウン式の形のフィールドもTextFieldのように作成することが可能です。

ImageField

主に、写真ファイルが入ります。

注意点

  • upload_toを指定しなければいけない。
    • 例: upload_to="image"
    • 上記のようにすることで、プロジェクト/media/image/ のなかに、アップロード写真が入ります。
    • 実際に、mediaの中に、写真ファイルが入り、dbには、写真へのパスが保存されます。
  • 何もしなければ、jpgファイルしか受け付けません。
    • .pngなどを扱うためにはpythonのイメージを取り扱う pillowというライブラリが必要になります。

FileField

主に、不特定のファイルが入ります。
注意点は、ImageFieldを参照。

IntegerField

主に、下記の範囲で数値が入ります。
2147483648 ~ -2147483647

例えば、扱う数値が低いとわかっている場合は、
SmallIntegerFieldなども存在します。
下記の範囲で数値が入ります。
32768 から -32767

反対に、かなり大きな数値を扱えるBigIntegerFieldも存在します。

また、フィールドの引数として、数値の下限や上限を決めたりすることもできます。

BooleanField

主に、True か False が入ります。
Pythonのbool型として扱われます(文字列ではありません)
よく使います。

使用例

  • 公開フラグ
  • 削除フラグ
  • etc...

DateField, DateTimeField

主に、時間を扱うフィールドです。
DateFieldの場合は、日にちまでしか、入りません。
DateTimeField の場合は、秒数まで入ります。
また、BooleanFieldと同じく、PythonのDate(Datetime)型として扱われます。

ForeignKey

主に、外部キーを扱うフィールドで、他のテーブルと紐づけるために使われます。
外部キーについては、別途、別のシリーズで扱います。

例えば、Categoryというテーブルがあり、

class Category(models.Model):
    name = models.CharField()

上記のようなテーブルで、
nameが政治というカテゴリが存在するとしましょう。

Article テーブルが以下のような場合、

class Article(models.Model):
    title = models.CharField()
    category = models.ForeignKey(Category, on_delete=models.CASCADE)

例えば、"トランプ政権崩壊"というtitleの記事を作成した場合に、先ほどの"政治"というカテゴリのテーブルと紐づけることができます。

注意点

  • ForeignKeyを作る場合、on_delete という引数を指定しないとエラーが出ます。これは、参照先が、削除された場合に、紐づいているテーブルをどうするか、というものです。
    • on_delete = models.CASCADE
      • 上記のようにした場合は、該当のArticleテーブルは一緒に削除されます。
    • on_delete = models.PROTECT
      • 上記の場合、該当のテーブルは、削除されなくなります。
    • その他にもたくさんありますが、ここでは触れません・

尚、ForeignKeyにおいて、 Articleテーブル から見た Categoryテーブルは、一つのみですが、
Categoryテーブルから見たArticleテーブルは、複数存在することがあります。
なので、リレーションは 一対多 になります。

ManyToManyField

主に、多対多のリレーションを作るときに、使います。 * on_delete は必要ありません。

OneToOneField

主に、一対一のリレーションを作るときに、使います。 * 仮に複数紐づけようとするとエラーになるので、気をつけてください。

ManyToManyとOneToOne は少し、難易度が高いので、ここでは、最小限しか触れないでおきます。


そのほかにも、指定できるフィールドには下記のものがあります。(名前と内容だけ)

その他のField

  • URLField (URLパスを入れることができる)
  • SlugField (URLのパスに対応した文字しか入れれない文字列 -> 半角英数字など)
    • 正規表現などで制限をかける必要がなくなる
  • EmailField (メールアドレスを入れることができる。@がない場合などに弾くことができる)
  • PositiveIntegerField(マイナスの数字が絶対ない場合、Positiveを入れることで、容量を最適化できる)

ほかにもたくさんあります。

ほとんど全てのフィールドには、共通して指定できるパラメーターがあります。

  • null
    フィールドがnullになっても良いかどうか
    例: null=True
    ケース: 既存のテーブルに後から、フィールドを追加する場合、null=Trueにすることで、既に存在しているデータに追加された新フィールドの値をnullにすることができる

  • blank
    フィールドが空白になっても良いかどうか
    例: blank = True
    ケース: 値が空白でもOKかどうかを設定できる。上記のArticle において、カテゴリがなくても、データを作成したい場合、 blank=Trueにすると、実現できる

  • default
    デフォルト値を設定できる
    例: default = 1
    ケース: 初めから、値を設定することができる

  • verbose_name
    フィールドの表示名を変更できる
    例: verbose_name = "記事タイトル"
    ケース: Articleテーブルのデータを取得した時に、表示名を設定できる。本来、英語で、 title と返るが、日本語で、タイトル などに設定することができる。

ほかにも共通して設定できることがありますが、主に使うのは、上記の4点です!

他にも、class 自体に、様々な関数を設定することができますが、ここでは、最低限に留めておきます。
その他の、modelsの設計については、公式ドキュメントを参照ください。

おさらいとアウトプット

それでは、最後に、今回学んだことをアウトプットするため、実際の使用をイメージして、テーブルを作成してみます。

  • ブログを作って、記事を書く
  • 記事にカテゴリを入れる
  • 記事にコメントできるようにする

上記の三つを実現するためにテーブルを作成していきます。

必要なテーブル

  • Category (カテゴリ)
  • Article (記事)
  • Comment (コメント)

ポイント

  1. カテゴリを、記事に複数設定するため、ManyToManyを使用
  2. 記事に複数のコメントを紐づけるため、コメントにForeignKeyを使用
  3. 記事には、メインイメージを使用し、ステータスをIntegerで管理。削除は、フラグで実装する
  4. Article にて Categoryを呼び出すため、Comment にて Article を呼び出すために、上記のような順番でテーブルを記述していきます。

上記の定義で、実際にテーブルを作成していきます。

from django.db import models


class Category(models.Model):

    name = models.CharField(max_length=31, verbose_name="カテゴリ名")

    def __str__(self):
        return self.name

    class Meta:

        verbose_name_plural = "カテゴリ"


class Article(models.Model):

    title = models.CharField(max_length=62, verbose_name="タイトル")
    slug = models.SlugField(verbose_name="URLスラッグ(英語)")
    image = models.ImageField(upload_to="article_image", blank=True, verbose_name="記事のイメージ写真", help_text="登録しない場合は、デフォルトのイメージ写真を使用する")
    categories = models.ManyToManyField(Category, verbose_name="カテゴリ")
    body = models.TextField(verbose_name="本文")
    status = models.PositiveSmallIntegerField(default=1, verbose_name="公開ステータス", help_text="1:下書き, 2:公開")
    liked = models.IntegerField(default=0, verbose_name="いいね数")
    is_deleted = models.BooleanField(default=False, verbose_name="削除フラグ")
    creator = models.CharField(max_length=31, verbose_name="投稿者")
    created = models.DateTimeField(auto_now_add=True, verbose_name="投稿日時")
    modified = models.DateTimeField(auto_now=True, verbose_name="更新日")

    def __str__(self):
        return self.title

    class Meta:

        verbose_name_plural = "記事"



class Comment(models.Model):

    article = models.ForeignKey(Article, on_delete=models.CASCADE, verbose_name="記事", related_name="comments")
    commenter = models.CharField(max_length=31, verbose_name="コメント者名")
    body = models.TextField(verbose_name="コメント文")
    created = models.DateTimeField(auto_now_add=True, verbose_name="コメント投稿日時")

    def __str__(self):
        return self.article.title + ":{}のコメント".format(self.commenter)

    class Meta:

        verbose_name_plural = "コメント"

上記のmodels.pyだけで、カテゴリ、記事、コメントのDBテーブルの作成が完了です。
これだけで、早速、ブログやメディア発信などが簡単にできますね :)

以上、今回はDjangoのmodels.pyについて、基本的な部分を説明していきました。

Just Pythonではこれからも、Pythonを用いたWeb開発について(主にDjangoについて)わかりやすく説明していきます