Djangoのモデル、フォームの仕組み
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