Django には 2 種類のモデルのサブクラス化があります - 抽象基底クラスです。マルチテーブル継承。
抽象基底クラスは単独で使用されることはなく、データベース テーブルや識別の形式もありません。これらは、データベースではなくコードで共通フィールドのセットをグループ化することにより、コードを短縮する方法にすぎません。
例えば:
class Address(models.Model):
street = ...
city = ...
class Meta:
abstract = True
class Employee(Address):
name = ...
class Employer(Address):
employees = ...
company_name = ...
これは不自然な例ですが、ご覧のとおり、Employee
は ではなく、Address
どちらも ではありませんEmployer
。どちらにも住所に関連するフィールドが含まれています。この例には 2 つのテーブルしかありません。Employee
、およびEmployer
- であり、両方とも Address のすべてのフィールドを含んでいます。雇用主の住所は、データベース レベルで従業員の住所と比較することはできません。住所には独自のキーがありません。
ここで、複数テーブルの継承 (Address から abstract=True を削除) を使用すると、Addressはすべてそれ自体にテーブルを持ちます。これにより、3 つの異なるテーブルが作成されます。Address
、Employer
、およびEmployee
。雇用主と従業員の両方が、住所に戻る一意の外部キー (OneToOneField) を持ちます。
アドレスの種類を気にせずにアドレスを参照できるようになりました。
for address in Address.objects.all():
try:
print address.employer
except Employer.DoesNotExist: # must have been an employee
print address.employee
各アドレスには独自の主キーがあります。つまり、4 つ目のテーブルに独自に保存できます。
class FakeAddresses(models.Model):
address = models.ForeignKey(Address)
note = ...
マルチテーブル継承はPost
、ポストのタイプを気にせずにタイプのオブジェクトを操作する必要がある場合に求められるものです。サブクラスから Post フィールドのいずれかにアクセスすると、結合のオーバーヘッドが発生します。ただし、オーバーヘッドは最小限に抑えられます。これは一意のインデックス結合であり、信じられないほど高速です。
へのアクセスが必要な場合は、クエリセットPost
で使用することを確認してくださいselect_related
。
Events.objects.select_related(depth=1)
これにより、親データを取得するための追加のクエリが回避されますが、結合が発生します。そのため、投稿が必要な場合にのみ select related を使用してください。
最後に 2 つのメモ。投稿がお知らせとイベントの両方になる場合は、従来のことを行い、ForeignKey を介して投稿にリンクする必要があります。この場合、サブクラス化は機能しません。
最後に、結合が親と子の間でパフォーマンスが重要な場合は、抽象継承を使用する必要があります。Generic Relations を使用して、パフォーマンスの重要度がはるかに低いテーブルから抽象的な投稿を参照します。
一般的なリレーションは、基本的に次のようなデータを保存します。
class GenericRelation(models.Model):
model = ...
model_key = ...
DeletedPosts(models.Model):
post = models.ForeignKey(GenericRelation)
これは SQL で結合するのがはるかに複雑になります (django がそれを支援します) が、単純な OneToOne 結合よりもパフォーマンスが低くなります。このルートをたどる必要があるのは、OneToOne 結合がアプリケーションのパフォーマンスに深刻な悪影響を与える可能性が低い場合だけです。