リレーションとは
データ同士の関連性を表す
通常classが違うと別のデータ扱い
たとえ
excel
- classが違う=sheetが違う
- なので、データ同士の関係性を作るための特別な関数を使う
今回の場合
SQliteを使用
アニメの情報と声優の情報を分ける
- アニメ:タイトル:リゼロ、放送開始年:2016年、放送時期:春
- 声優:小林裕典、高橋李依、内山夕実、水瀬いのり、村川梨衣、新井里美、子安武人...
フォームで評価等
- 評価:ss, s, a, b, c
- ジャンル:ファンタジー、SFなど
1. ForeignKey
のオプション
ForeignKey
には、関連付けの動作を細かく制御するオプションがあります。
主なオプション
-
on_delete
-
models.CASCADE
: 親オブジェクトが削除されたら、関連するオブジェクトも削除される(デフォルト) -
models.PROTECT
: 親オブジェクトが削除されるのを防ぐ -
models.SET_NULL
: 親オブジェクトが削除されたら、関連するフィールドをNULL
にする -
models.SET_DEFAULT
: 親オブジェクト削除時に、デフォルト値に設定 -
models.SET()
: 指定した値をセットする -
models.DO_NOTHING
: 何もしない(データ整合性が崩れる可能性があるため推奨されない)
-
-
related_name
- 逆参照時に使う名前を指定(例:
author.books.all()
)
- 逆参照時に使う名前を指定(例:
-
related_query_name
- 逆参照時のフィルタ名(例:
Book.objects.filter(author__books__title="Python")
)
- 逆参照時のフィルタ名(例:
-
db_index
- データベースインデックスを追加 (
True
にすると検索速度が向上)
- データベースインデックスを追加 (
2. ManyToManyField
のオプション
ManyToManyField
には、中間テーブルの動作やリレーションの管理を制御するオプションがあります。
主なオプション
-
related_name
- 逆参照時の名前を設定(例:
course.students.all()
)
- 逆参照時の名前を設定(例:
-
related_query_name
- 逆参照時のフィルタ名を設定(例:
Student.objects.filter(course__students__name="John")
)
- 逆参照時のフィルタ名を設定(例:
-
through
- 中間テーブルを指定(例:
Enrollment
モデルを使ってカスタム中間テーブルを定義)
- 中間テーブルを指定(例:
-
symmetrical
- 自動的に双方向の関係になるかどうか(デフォルトは
True
)
- 自動的に双方向の関係になるかどうか(デフォルトは
-
db_index
- インデックスを追加 (
True
にすると検索速度向上)
- インデックスを追加 (
簡単なまとめ
オプション | ForeignKey |
ManyToManyField |
---|---|---|
on_delete |
✅ | ❌ |
related_name |
✅ | ✅ |
related_query_name |
✅ | ✅ |
db_index |
✅ | ✅ |
through |
❌ | ✅ |
symmetrical |
❌ | ✅ |
流れ
models.py → scripts.py
役割
dbの基礎 (リレーション)→ 選択肢
models.py
- ManyToManyField - フォーム、検索用
- ForeignKey - インポート、詳細用
# アニメモデル
class Anime(models.Model):
anime_id = models.CharField(max_length=200, unique=True, verbose_name='アニメID')
value = models.ManyToManyField(Value, verbose_name='評価', blank=True, related_name='animes_value')
def __str__(self):
return self.title if self.title else "不明なアニメ"
#評価(全クラス共通)モデル
class Value(models.Model):
name = models.CharField(max_length=200, unique=True, verbose_name='評価')
def __str__(self):
return self.name
# キャストモデル リレーション多対多
class Cast(models.Model):
anime = models.ForeignKey(Anime, on_delete=models.CASCADE,
related_name='casts', verbose_name="アニメ")
name = models.CharField(max_length=200, blank=True, null=True, verbose_name='声優名') # 空のデータを許容
def __str__(self):
return self.name if self.name else "不明なキャスト"
scripts.py
- 選択肢
# Valueのデータ登録
for name in ['SS', 'S', 'A', 'B', 'C', 'D']:
Value.objects.get_or_create(name=name)