におけるモデル継承
問題
私は現在、医療機器を販売する会社のために働いています.数ヶ月前、私たちの販売担当者が簡単に私たちの製品を検索し、お客様に送信するための引用符を構築することができますdjangoを使用してシステムを構築することを求められた.システムの要件のいくつかは以下の通りです.
Product
すべての型に共通の属性を持つクラスは、各製品の型は、独自の、一意の属性を追加するサブクラスにすることができます.Product
Product
オブジェクトタイプと無知のままProduct
Djangoの管理サイトに個別に複数テーブル継承
複数テーブル継承は、スーパークラスと各サブクラスが自分のデータベーステーブルにマップする場所です.共有フィールドは、SuperClassテーブルに格納され、型に固有のフィールドがそれぞれのテーブルに格納されます.各サブクラステーブルには、親クラステーブルの対応する行のIDが含まれている列が追加されます.Djangoでは、モデルクラスはこのように見えるかもしれません
from django.db import models
class Product(models.Model):
part_number = models.CharField(max_length=25)
price = models.CharField(max_length=25)
class Label(Product):
dimensions = models.CharField(max_length=25)
class FaceMask(Product):
COLOR_CHOICES = [
('Blue', 'Blue'),
('White', 'White')
]
color = models.CharField(max_length=25, choices=COLOR_CHOICES)
そして、テーブルはこのようになりますグレート.今、我々は個々に編集することができます管理者に各製品の種類を追加することができます.また、一般的な製品を追加することができます
Quote
このようにclass Quote(models.Model):
name = models.CharField(max_length=25)
products = models.ManyToManyField(Product)
単一テーブル継承
名前が意味するように、単一のテーブル継承は、スーパークラスの属性とすべてのサブクラスを格納するために1つのテーブルだけを使用します.サブクラス型をテーブルで区別する代わりに
type
列は、特定の行が対応するオブジェクトの型を知るために使用されます.Djangoでは以下のようになります.class Product(models.Model):
# Type field
TYPE_CHOICES = [
('Label', 'Label'),
('Face Mask', 'Face Mask')
]
product_type = models.CharField(max_length=25, choices=TYPE_CHOICES)
# Common Fields
part_number = models.CharField(max_length=25)
price = models.CharField(max_length=25)
# Label fields
label_dimensions = models.CharField(max_length=25)
# Face Mask fields
COLOR_CHOICES = [
('Blue', 'Blue'),
('White', 'White')
]
face_mask_color = models.CharField(max_length=25, choices=COLOR_CHOICES)
そして、テーブルはこのようになります私は最初にどのように個々のタイプを管理者に示すことができたかについて、私に不明瞭でしたので、私は遺産をするこの方法に不満を持っていました.それは、私がDjangoの代理モデルと
Manager
クラス.プロキシモデルを使えば、マルチテーブル継承と同じ効果を達成することができます.class LabelManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(product_type='Label')
class Label(Product):
objects = LabelManager()
class Meta:
proxy = True
class FaceMaskManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(product_type='Face Mask')
class FaceMask(Product):
objects = FaceMaskManager()
class Meta:
proxy = True
ジャンゴManager
クラスは基本的に、オブジェクトを照会するとき、デフォルトフィルタを適用することができます.上記のコードを使用してLabel.objects.all()
得るLabel
例えばオブジェクト.The proxy = True
メタオプションは、Djangoに別々のテーブルを作成しないように指示しますLabel
or FaceMask
オブジェクト.我々は、管理者にプロキシモデルを登録することができます、我々はちょうど我々が適切なフィールドを表示する管理者に指示することを確認する必要があります.@admin.register(Label)
class LabelAdmin(admin.ModelAdmin):
fields = ('part_number', 'price', 'dimensions')
@admin.register(FaceMask)
class FaceMaskAdmin(admin.ModelAdmin):
fields = ('part_number', 'price', 'color')
何を選んだ
単一のテーブル継承の最大の利点は、1つのテーブルに1つのクエリを実行するだけで、必要な情報を取得する必要があります.複数テーブル継承は、スーパークラスとサブクラステーブルを結合する必要があります.我々は我々が多くの製品質問をしているということを知っていました、そして、我々はすべてのものについて心配しました
JOIN
操作は、アプリケーションを遅くします.また、私たちは当初、2種類の製品タイプのみを格納することを計画していました.我々は、これらの理由のために我々の製品データをモデル化するために、単一のテーブル継承を選びました.しかし、私は、マルチテーブル継承がより良い選択であったかもしれないと思い始めています.アプリケーションの要件を変更すると、いくつかの製品の種類を格納する必要があります.製品のテーブルは、私たちの製品の種類の間に共通の多くの属性がないので、空白のエントリで肥大化している.これは、製品のテーブルを混乱させると管理することは困難になり、私はそれが遅いクエリのトレードオフの価値があると思います.ありがたいことに、単一のテーブルの継承がうまく機能し、私が言及したように、我々はそれのパフォーマンスの利点を得るか.
結論
私は、あなたのサブクラスが一般的に多くの分野を持たないならば、マルチテーブル継承が行く方法であるということをここで学んだレッスンを仮定します.これは、はるかに効率的なメモリの場合は、空白のエントリの多くのデータベースをブロックするリスクがないです.単一のテーブル継承は、常に効率的ではありません
JOIN
操作が必要です.ほとんどのものと同様に、トレードオフがあり、正しい選択はあなたのユースケースによって異なります.Reference
この問題について(におけるモデル継承), 我々は、より多くの情報をここで見つけました https://dev.to/zachtylr21/model-inheritance-in-django-m0jテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol