💡

Djangoのモデル、フォームの仕組み

2024/04/22に公開

Djangoのモデルの基礎

すぐに忘れてしまうので、モデルとフォームの仕組みを備忘録としてまとめておく

モデル系

更新のリファレンスはこちら
Djangoのモデルフィールド
Djangoのモデルメタ

フォーム系

DjangoのフォームAPI
Djangoのフォームフィールド
Djangoのフォームビルトインウィジェット

インポート

from django.db import models

モデルの基本の仕組み

初期状態では、クラス変数名がテーブルのカラム名に相当します。クラス変数に代入するオブジェクトの型がカラムの型を表します

文字列型のカラムなら「CharField」「TextField」、整数型のカラムなら「IntegerField」、日付方なら「DateField」「DateTimeField」などを指定します

from django.db import models

class Hoge(models.Model):
    name=models.CharField(max_length=255)
    age = models.IntegerField()
    birthday = models.DateField()

フィールドのオプション

フィールドクラスのコンストラクタで様々なオプションを指定可能です。フィールドによって、必須項目であったり、使えないオプションなどもあるが、大体同じような動きになります。以下のオプションはす全てのフィールドで有効です。省略も可能です

null

Trueにすると、テーブルのカラムは「DEFAULT NULL」になります。Djangoのモデルで登録する場合、カラムを省略すると、「NULL」になります。CharFieldの場合、空文字が代入します。IntergerField、DateFieldでは、NULLを代入します。省略可能です。省略した場合、デフォルトは False です

class Hoge(models.Model):
    name=models.CharField(
        max_length=255,
        null=True,
    )
    age = models.IntegerField(
        null=True,
    )
    birthday = models.DateField(
        null=True,
    )

blank

Trueにすると、フィールドを空にできます。省略可能です。省略した場合、Falseです

nullの場合、テーブルのカラム定義に影響しますが、blankの場合、テーブルのカラムには影響がないように見えます(たぶん)。「NOT NULL」になっています

「blank=True」にした場合、CharFieldでは、空が許容されます。IntergerField、DateFieldでは、結局、空にはできない。フォームとの関連性があるかも?

class Hoge(models.Model):
    name=models.CharField(
        max_length=255,
        blank=True,
    )
    age = models.IntegerField(
        blank=True,
    )
    birthday = models.DateField(
        blank=True,
    )

choices

選択肢を提供します。省略可能です。省略した場合、選択肢自体がないです

シーケンスで指定します。以下の例では二次元タプルで指定しています。二次元目の1番目の値がDBに格納する値、2番目の値が、フォームなどに表示する値です

モデルを直接利用して、テーブルに格納する場合、choicesは関係なく、自由に値を設定できます。choicesが意味を持つのは、フォームクラスと連動した場合です。フォームクラスと連動した場合、ウィジェットがセレクトボックスになります。chocesの選択肢をセレクトボックスで表現します。chocesがない場合、各フィールドクラスに割り当てられているデフォルトのウィジェットで表示します

from django.db import models
import datetime from datetime

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        choices=(
            ('apple', 'リンゴ'),
            ('orange', 'オレンジ'),
            ('melon', 'メロン'),
        )
    )
    age = models.IntegerField(
        choices=(
            (10, '10才'),
            (20, '20才'),
            (30, '30才'),
        )
    )
    birthday = models.DateField(
        choices=(
            (datetime.strptime('2020-05-05',"%Y-%m-%d").date(), '5月5日'),
            (datetime.strptime('2020-08-10',"%Y-%m-%d").date(), '8月10日'),
            (datetime.strptime('2020-12-20',"%Y-%m-%d").date(), '12月20日'),
        )
    )

db_column

テーブルのカラム名を指定します。省略可能です。省略した場合、クラス変数名をカラム名に設定します。あくまでもテーブルのカラム名が変更されるだけです。Djangoのプログラム処理では、変数名を利用して処理を行います

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        db_column='apple', # カラム名はapple
    )
    age = models.IntegerField(
        db_column='orange', # カラム名はorange
    )
    birthday = models.DateField(
        db_column='melon', # カラム名はmelon
    )

db_comment

データベース定義のカラムにコメントを設定します

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        db_comment='名前のカラム',
    )
    age = models.IntegerField(
        db_comment='年齢のカラム',
    )
    birthday = models.DateField(
        db_comment='誕生日のカラム',
    )

db_index

Trueにすると、テーブルのカラムにインデックスを張ります

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        db_index=True,
    )
    age = models.IntegerField(
        db_index=True,
    )
    birthday = models.DateField(
        db_index=True,
    )

db_tablespace

テーブルスペースを指定します

Oracle、PostgreSQLはテーブルスペースをサポートしています。MySQLにはテーブルスペースの機能がありません。機能がない場合、動作しません

default

カラムのデフォルト値を指定します。テーブル定義には影響していない。あくまでもDjangoでのモデル処理でのデフォルト値になる

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        default='Bob',
    )
    age = models.IntegerField(
        default=12,
    )
    birthday = models.DateField(
        default='2010-05-15',
    )
from example.models import Player
p = Player()
p.save
# この場合、各カラムにデフォルトが代入されている

フォームクラスと連動した場合、ウィジェットでのデフォルト値に反映されています

editable

editable=Falseの場合、管理画面での編集画面、フォームクラスと連動した画面で表示されません。省略可能です。省略した場合、デフォルト値はTrueです

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        editable=False,
        null=True,
    )
    age = models.IntegerField(
    )
    birthday = models.DateField(
        editable=False,
        null=True,
    )

editable=Falseに設定したフィールドはフォームクラスの「fields」に追加するとエラーになります

class PlayerForm(forms.ModelForm):
    class Meta:
        model = Player
        fields = ['name', 'age','birthday'] # nameとbirthdayは編集できない

error_messages

フィールドクラスのエラーメッセージを上書きします。ディクショナリで指定します。省略可能です。省略した場合、デフォルトのエラーメッセージを表示します

ディクショナリのキーは、以下のようなものがあります。
null、blank、invalid、invalid_choice、unique、unique_for_date

フィールドクラスによって、独自のエラーメッセージのキーがあります。とはいえ、実際のエラーメッセージはフォームクラスで設定するのでいあまり意味がないような

help_text

各フィールドの補助テキストを設定します。フォームクラスと連動した場合、各入力パーツに補助用テキストを表示可能です

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        help_text = '名前だよ',
    )
    age = models.IntegerField(
        help_text = '年齢だよ',
    )
    birthday = models.DateField(
        help_text = '誕生日だよ',
    )

primary_key

primary_key=Trueにした場合、そのフィールドがモデルのプライマリーキーのカラムになります

primary_key=Trueをモデルクラス内のフィールドにも指定しない場合、Djangoが自動的にプライマリーキーのカラムを自動的に生成します。そのため、primary_key=Trueを指定する必要はありません

デフォルトのプライマリーキーの設定を上書きする場合、primary_keyの設定を行う

primary_keyのカラムの型は設定ファイルの「DEFAULT_AUTO_FIELD」により決定されます。基本的にはオートインクリメントになりますが、設定を変更することも可能です

primary_key=Trueにする場合、null=Falseであり、unique=Trueになります。つまり、NULLを許容しない、かつユニーク制約を適用します。これはテーブルのプライマリーキーの考え方と同じです

モデルクラス内ではprimary_key=Trueは1個のカラムだけに指定します

以下の例では、UUIDを利用したプライマリーキーのカラムを独自に設定します

import uuid

class Player(models.Model):
    id = models.UUIDField(
        primary_key=True, 
        default=uuid.uuid4, 
        editable=False
    )
    name=models.CharField(
        max_length=255,
    )
    age = models.IntegerField(
    )
    birthday = models.DateField(
    )

unique

unique=Trueにすると、そのカラムはユニークになります。テーブルにユニーク制約を設定します。重複した登録はエラーになります

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        unique=True,
    )
    age = models.IntegerField(
    )
    birthday = models.DateField(
    )

unique_for_date

DateField、DateTimeFieldで利用します。unique_for_date=Trueを設定すると、Date、DateTimeのカラムがユニークになります

unique_for_month

DateField、DateTimeFieldで利用します。unique_for_month=Trueを設定すると、Date、DateTimeのカラムで月がユニークになります

unique_for_year

DateField、DateTimeFieldで利用します。unique_for_year=Trueを設定すると、Date、DateTimeのカラムで年がユニークになります

verbose_name

カラム名に表示用の名称を指定します。フォームクラスと連動した場合、ラベル、プレイスホルダーにも利用されます

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        verbose_name='名前',
    )
    age = models.IntegerField(
        verbose_name='年齢',
    )
    birthday = models.DateField(
        verbose_name='誕生日',
    )

validators

モデルクラス用のバリデータに指定します。モデルクラスのバリデーションを設定する場合に指定します。リストで指定します

バリデータの種類

フィールドクラス

フィールドクラスの種類

クラス名 説明 デフォルトのウィジェット
AutoField 自動的にインクリメントする IntegerField です。通常は直接使う必要はありません
BigAutoField 64ビットの数値です。1 から 9223372036854775807 までの数
BigIntegerField 64ビットの数値です。-9223372036854775808 から9223372036854775807までの数値 NumberInput
BinaryField バイナリーデータを格納する
BooleanField True / False を格納する CheckboxInput
CharField 文字列を格納する。大容量の文字列の場合、TextFieldを利用する TextInput
DateField 日付型 TextInput
DateTimeField DateTime型 DateTimeInput
DecimalField 固定小数点 localizeがFalseのとき、NumberInputで、そうでなければTextInput
DurationField 時刻の期間を保持する
EmailField Emailを格納する EmailInput
FileField ファイルアップロードのフィールド
FilePathField ファイルシステム上のディレクトリのファイル名に限定されるCharField
FloatField 浮動小数点数 TextInput
GenericIPAddressField Pv4 か IPv6 のアドレスで、文字列フォーマットです (例: 192.0.2.30 ないし 2a02:42fe::4) TextInput
ImageField FileField から全ての属性とメソッドを継承して、さらにアップロードされたオブジェクトが有効な画像であることを検証
IntegerField 整数で-2147483648から2147483647 NumberInput or TextInput
JSONField JSON形式の文字列
PositiveBigIntegerField 正の整数、0から9223372036854775807 NumberInput
PositiveIntegerField 正の整数、0から2147483647 NumberInput
PositiveSmallIntegerField 正の整数、0から32767 NumberInput
SlugField 短い文字列
SmallAutoField AutoFieldで、1かあ32767
SmallIntegerField 整数、-32768から32767
TextField 大容量の文字列 Textarea
TimeField datetime.time インスタンス
URLField URLの文字列
UUIDField UUIDを保持する

関連性の定義

種類 関連性のフィールド 説明
多対1 ForeignKey 多対1の関係性、多側に設定する
多対多 ManyToManyField 多対多の関係性、どちら側でも
1対1 OneToOneField 1対1の関係性

ForeignKey

外部制約を実現します。多対1の関係性を作ります。多側のモデルクラスに設定します

class Category(models.Model):
    name = models.CharField(
        verbose_name='名前',
        max_length=100
    )

class Item(models.Model):
    name = models.CharField(
        verbose_name='名前',
        max_length=100
    )
    category = models.ForeignKey(
        Category,
        verbose_name='カテゴリ',
        on_delete=models.CASCADE
    )

on_deleteは必須で、削除時の動作を設定します。

on_delete=models.CASCADEの場合、1側を削除すると、関連する多側も自動的に削除します
on_delete=models.PROTECTの場合、1側を削除しても、関連する多側は削除しません

ManyToManyField

多対多の関係性を実現します。中間テーブルを自動的に作成します

class Person(models.Model):
    name = models.CharField(max_length=50)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField()

OneToOneField

1対1の関係性を実現します

class User(models.Model):
    name = models.CharField(
        max_length=50
    )

class SpecialUser(models.Model):
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
    )
    special = models.CharField(
        max_lenght=50,
    )

フォームクラス

フォームクラスの利用方法です。ここでは、モデルと連動するModelFormについてです

モデルクラス

class Player(models.Model):
    name=models.CharField(
        max_length=255,
        verbose_name='名前',
    )
    age = models.IntegerField(
        verbose_name='年齢',
    )
    birthday = models.DateField(
        verbose_name='誕生日',
    )

フォームクラス

ModelFormを継承することで、モデルと連動したフォームを作成します。Metaクラスでモデル名、利用するフィールド名を指定します。fieldsで指定したフィールドがフォームに表示されます。あるいは、excludeで指定したカラムをモデルのフィールドから除外することも可能です

class PlayerForm(forms.ModelForm):
    class Meta:
        model = Player
        fields = ['name', 'age', 'birthday']

フォームのフィールドクラス

フォームにもフィールドクラスの指定が可能です

(組み込みフィールドクラス)[https://docs.djangoproject.com/ja/4.2/ref/forms/fields/#built-in-field-classes]

Discussion