【非公式翻訳】ForeignKey in Django公式ドキュメント
Django公式ドキュメントのForeignKeyの日本語訳です。
間違いがありましたら、コメント欄にてご指摘お願いします!
ForeignKey
class ForeignKey(to, on_delete, **options) [ソース]
多対一のリレーションです。2つの位置引数を必要とします。すなわち、そのモデルに紐付いているクラスとon_deleteオプションです。
再帰的なリレーションを築くために(別の表現をすると、多対一のリレーションをもつオブジェクトをつくるために)、models.ForeignKey('self', on_delete=models.CASCADE)を利用します。
未定義のモデルに紐づくリレーションを築く必要がある場合、モデルオブジェクト自体を使うのではなく、モデルの名前を使うことができます。
from django.db import models class Car(models.Model): manufacturer = models.ForeignKey( 'Manufacturer', on_delete=models.CASCADE, ) # ... class Manufacturer(models.Model): # ... pass
具体的なモデルとしてサブクラス化され、抽象モデルのapp_modelと関連しなくなった場合、抽象モデルを利用したこの方法で定義されるリレーションは決められます。
products/models.py
from django.db import models class AbstractCar(models.Model): manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE) class Meta: abstract = True
production/models.py
from django.db import models from products.models import AbstractCar class Manufacturer(models.Model): pass class Car(AbstractCar): pass # Car.manufacturer will point to `production.Manufacturer` here.
他のアプリケーションで定義されたモデルを参照するには、フルのアプリケーションラベルをつけてモデルを明示的に特定する必要があります。例えば、上記のManufacturerモデルが、productionという他のアプリケーションで定義される場合、下記のようにします。
class Car(models.Model): manufacturer = models.ForeignKey( 'production.Manufacturer', on_delete=models.CASCADE, )
遅延評価と呼ばれる※1この参照方法は、2つのアプリケーション間で回帰する依存関係?を解消します。
データベースのインデックスは自動的にForeignKeyに作成されます。db_indexをFalseにすることでこれを無効にすることができます。 一貫性のためにJOINではなくForeignKeyを作っている場合や、部分インデックスまたは複合インデックスのような代替的なインデックスを作成している場合、インデックスの重複を避けたくなるでしょう。
データベースでの表記方法
Djangoは裏で、データベースのカラム名を作る際にフィールド名の後ろに"_id"をつけます。上記の例では、Carモデルはmanufacturer_idカラムを持ちます。(db_columnを指定することで、明示的にこれを変更することができます。)しかし、カスタムSQLを書かない限り、コードでデータベースのカラム名を扱うべきではありません。常にモデルのオブジェクトのフィールド名を扱うべきです。
引数
ForeignKeyは、リレーションがどのように機能するかの詳細を定義した他の引数を受け付けます。
ForeignKey.on_delete
ForeingKeyで参照されているオブジェクトが削除された時、Djangoはon_delete引数によって指定されたSQL制約をエミュレートします。例えば、もしNULLにできるForeignKeyがあり、参照されたオブジェクトが削除された際にNullをセットしたいとします:
user = models.ForeignKey( User, models.SET_NULL, blank=True, null=True, )
on_deleteは、データベースにSQL制約を作成しません。データベースレベルのカスケードのオプションは後々実装される予定です。
on_deleteの設定可能な値は、django.db.modelsで確認できます:
カスケードの削除。DjangoはON DELETE CASCADE でSQL制約の振る舞いをエミュレートし、ForeignKeyを含むオブジェクトを削除します。
関連したモデルにModel.delete()は呼ばれませんが、削除されるすべてのオブジェクトにpre_deleteとpost_deleteの信号が送られます。
- PROTECT[ソース]
django.db.IntegrityErrorのサブクラスであるProtectedErrorを発生させることで、参照されたオブジェクトが削除されるのを防ぎます。
- SET_NULL[ソース]
ForeignKeyをNullにセットします; これはnullがTrueである場合のみ可能です。
- SET_DEFAULT[ソース]
ForeinKeyをデフォルト値にセットします; ForeinKeyのデフォルトを必ずセットしなくてはなりません。
- SET()[ソース]
ForeinKey、もしくはcallableが渡された場合はそれを呼び出した結果をSET()にに渡される値にセットします。ほとんどの場合、callableを渡すのは、models.pyをインポートした時にクエリーを実行することを避けるために必要です。
from django.conf import settings from django.contrib.auth import get_user_model from django.db import models def get_sentinel_user(): return get_user_model().objects.get_or_create(username='deleted')[0] class MyModel(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET(get_sentinel_user), )
- DO_NOTHING[ソース]
何も実行しません。もし、データベースバックエンドが参照整合性を強要する場合、ON DELETE制約をデータベースのフィールドに自動的に追加しない限り、 IntegrityErrorを引き起こします。
ForeignKey.limit_choices_to
ModelFormかadminを利用してこのフィールドがレンダーされている時に、選択可能な選択肢を制限します。(デフォルトでは、クエリーセットのすべてのオブジェクトを選択することができます。)辞書型、Qオブジェクト、辞書型かQオブジェクトを返すcallableが利用可能です。
staff_member = models.ForeignKey( User, on_delete=models.CASCADE, limit_choices_to={'is_staff': True}, )
例えば上記は、is_staff=TrueであるUsersしか選べないようなModelFormのフィールドを作成します。これはDjango adminに役立ちます。
例えば、下記のように、 日付の選択肢を制限するためにPythonのdatetimeモジュールと接続して利用する時にcallableフォームも役立ちます。
def limit_pub_date_choices(): return {'pub_date__lte': datetime.date.utcnow()} limit_choices_to = limit_pub_date_choices
limit_choices_toがQオブジェクトである、もしくはQオブジェクトを返す場合(Qオブジェクトは、複雑なクエリーに役立ちます)、limit_choices_toがModelAdminのraw_id_fieldsのリストに入っていない時にadminで利用できる選択肢に影響します。
注釈
limit_choices_toがcallableに利用されている場合、新しいフォームが初期化されるたびに呼び出されます。また、例えばmanageコマンドやadminによってモデルが有効にされた時にも呼び出されます。adminは何回も、多様なエッジケースにおいてフォームの入力を有効化するためにクエリーセットを構築します。そのため、callableが何回も呼び出される可能性があります。
ForeignKey.related_name
あるオブジェクトと関連しているオブジェクトとの関係に利用する名前です。また、related_query_name(ターゲットとなるモデルからの逆引きされる名前に利用するための名前)に使うためのデフォルト値でもあります。)全ての説明と例を見るには、「リレーションシップ "反対向き” を理解する」をご参照ください。抽象モデルとの関係を定義する時はこの値をセットする必要があることを心に留めておいてください。それによって、いくつかの特別なシンタックスを利用できます。
Django裏側での関係を生成して欲しくない場合、related_nameに'+'や'+'で終わる名前をつけてください。例えば、これによってUserモデルがこのモデルと裏側での関係を持たないようにします。
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='+',
)
ForeignKey.related_query_name
ターゲットとなるモデルの逆引きに利用するための名前です。設定すると、related_nameまたはdefault_related_nameのデフォルトとなります。もしくはそのモデル名のデフォルトとなります。
# Declare the ForeignKey with related_query_name class Tag(models.Model): article = models.ForeignKey( Article, on_delete=models.CASCADE, related_name="tags", related_query_name="tag", ) name = models.CharField(max_length=255) # That's now the name of the reverse filter Article.objects.filter(tag__name="important")
related_nameのように、related_query_nameは特別なシンタックスを通してapp labelとクラスの補間をサポートします。
ForeignKey.to_field
関連しているオブジェクトのフィールドです。デフォルトでは、Djangoは関連したオブジェクトのプライマリーキーを利用します。異なるフィールドを参照したい場合、そのフィールドをunique=Trueにしなければなりません。
ForeignKey.db_constraint
そのForeignKeyの制約をデータベースに作るかどうかの制御をします。デフォルトは、Trueですが、ほぼあなたがしたいことでしょう。これをFalseにすることはデータの一貫性からして良くないです。ここで、これを行いたい場合のシナリオを用意しました。
妥当ではないレガシーなデータがある場合
データベースを破損した場合
Falseにセットした場合、存在しない関連したオブジェクトにアクセスしたらDoesNotExistを例外として吐き出します。
ForeignKey.swappable
ForeignKeyがスワップできるモデルを指している時のマイグレーションフレームワークの動きを制御します。True(デフォルト)の場合、ForeignKeyがsettings.AUTH_USER_MODEL(もしくは、他のスワップできるモデルに関するsettings)の現在の値と整合するモデルを指している場合、モデルに直接する保管するのではなく、関係はsettingsの参照を利用するマイグレーションに保管されます。
例えばモデルが常にスワップインされたモデル(例えば、カスタムユーザーモデルのために特別に設計されたプロフィールモデル)を指すと確信している場合のみ、Falseをオーバーライドしたくなるでしょう。
Falseにすることは、スワップできるモデルがスワップアウトされても参照できるという意味ではありません。Falseはただ、ForeignKeyと作られたマイグレーションはあなたが特定したモデルを常に参照することを意味します(例えば、あなたがサポートしていないUserモデルを実行しようとすると落ちます。)
不安な場合、デフォルトであるTrueのままにしておいてください。
※1 Django特有の他の言い方があるように思えるので合ってる自信がありません汗