PUROGU LADESU

ポエムがメインのブログです。

【Django】モデル

モデルを定義してマイグレーションしてDBを作成するのが目的です。
あと自動生成される管理画面の出来栄えはモデルに依存するでしょう。

モデル | Django ドキュメント | Django

models.Model

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

django.db.models.Model のサブクラスにします。
id フィールドは自動的に追加されますが、しないこともできます。
各フィールドはField クラスにする。フィールドはデータ型によって選択します。
フィールド名はpython予約語やダブルアンダースコアは使えない。

フィールドオプション

null: Trueでnull許容。デフォルトはFalse。nullはデータベース由来。
blank: Trueでブランクを許容。デフォルトはFalse。Falseはバリデーションで入力必須になる。
choices: 選択肢。タプルのリストで指定。タプルの1つめがDB値、2つ目が表示名になる。
表示名はget_FOO_display() メソッドで取得可能。

  SHIRT_SIZES = (
      ('S', 'Small'),
      ('M', 'Medium'),
      ('L', 'Large'),
  )

default: デフォルト値。
help_text: ウイジェットで表示できる説明。
primary_key: Trueにするとそのフィールドがモデルの主キーになる。値の変更は不可。ない場合はIntegerFieldが自動で追加される。

unique: 一意制約をつける。
verbose_name: 詳細フィールド名。最初の文字は大文字にしない。一部を除きキーワード引数を使わず第一引数に指定できる。

  • 自動インクリメント

id = models.AutoField(primary_key=True)
明示的にprimary_keyがどこにも設定されていない場合はAutoFieldのidフィールドが自動追加される。あれば追加されない。

リレーション

  • 多対一 (many-to-one) 関係

models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
親となるモデルをForeignKeyで定義する。on_deleteで親が消えたときに自分も削除する。

自己結合する場合は、models.ForeignKey('self')を使う。

リレーションシップフィールド
モデルフィールドリファレンス | Django ドキュメント | Django

  • 多対多 (many-to-many) 関係

toppings = models.ManyToManyField(Topping)
どちらか片方に定義する。両方にしない。

リレーションテーブルの追加フィールドを定義する場合は別途モデルを作成し
そこでForeignKeyを2つと追加フィールドをつける。

remove() 関連する中間モデルの全削除
clear()

  • 一対一 (one-to-one) 関係

user = models.OneToOneField

ForeignKeyとUniqueを設定したのと同じだが、関連モデルからの参照は単一オブジェクトを返す。
モデルを継承して拡張する方法もある。

モデルフィールドリファレンス | Django ドキュメント | Django

複数テーブルの継承
モデル | Django ドキュメント | Django


Meta

並び替えなど、フィールド以外のオプションを定義できる。

class Meta
  ordering = ["horn_length"]
  verbose_name_plural = "oxen"

Model Meta options | Django ドキュメント | Django


属性

  • objects

マネージャー。名前はobjects。クエリ操作のインターフェース。モデルのインスタンスを取り出す。

マネージャ | Django ドキュメント | Django

objects = models.Manager()

メソッド

モデルインスタンスを操作する

モデルインスタンスリファレンス
https://docs.djangoproject.com/ja/3.1/ref/models/instances/

モデルの継承

  • 抽象クラス

これでデータベースの作成はされなくなり、継承させる役割のみになる。継承させるならこちらのパターンになる場合が多いのでは。
逆にabstractを使わなければ、厳密に正規化されてベースモデルのテーブルが作成され、子モデルのテーブルは差分のみ作成される。one-to-oneの関係になり常に結合して使うことになる。

class Base(model.Model):
    class Meta:
      abstract = True
  • Meta の継承

定義しなければ親のMetaを継承。サブクラス化すれば親のMetaを拡張できる。

class CommonInfo(model.Model):
  class Meta(CommonInfo.Meta):
  • プロキシモデル

データベースに影響を与えず、既存のモデルの振る舞いだけ変えたい場合。
リリース済み既存のモデルを修正する場合は、プロキシモデルの利用を検討するとよいのかも。

class MyPerson(Person):
    class Meta:
        proxy = True
   ...

まとめ

意外とモデルの継承とone-to-one関係が重要な気がします。
モデルとしての役割分担だけでなく、どんなテーブル構成になるのか把握しておく必要があります。