別のモデルで複数の列を参照する外部キーを定義することは可能ですか?
たとえば、1つの外部キーは、製品テーブルの2列のインデックスとSQLステートメントを参照します。
FOREIGN KEY (product_category, product_id) REFERENCES product(category, id)
ところで、私は調べましたがdjango.contrib.contenttypes
、それがこの種のシナリオの完璧な解決策ではないと思います。
別のモデルで複数の列を参照する外部キーを定義することは可能ですか?
たとえば、1つの外部キーは、製品テーブルの2列のインデックスとSQLステートメントを参照します。
FOREIGN KEY (product_category, product_id) REFERENCES product(category, id)
ところで、私は調べましたがdjango.contrib.contenttypes
、それがこの種のシナリオの完璧な解決策ではないと思います。
まだサポートされていません。必要に応じて、チケットとそれを処理するための可能な方法があります。たぶんあなたはカスタムSQLを実行することさえできます
複数列の主キーのサポート
リレーショナルデータベースの設計では、テーブルの主キーとして一連の列を使用します。このセットに複数の列が含まれている場合、それは「複合」または「複合」主キーと呼ばれます。(用語の詳細については、データベースキーについて説明している記事をご覧ください)。現在、Djangoモデルはこのセットの単一の列のみをサポートしており、テーブルの自然な主キーが複数の列である多くの設計を拒否しています。Djangoは現在、これらのスキーマを操作できません。代わりに、冗長な単一列キー(「代理」キー)を導入する必要があります。これにより、アプリケーションは、任意のインスタンスでテーブルに使用するキーについて、任意の、またはその他の方法で不要な選択を行う必要があります。このページでは、Djangoにこれらの複合主キーをサポートさせる方法について説明します。ここで理解するための詳細はたくさんありますが、正しく実行されます。
現在のステータス
現在の状態では、問題は受け入れ/割り当てられ、作業中です。http://github.com/dcramer/django-compositepksに部分的な実装があります。実装により、複合主キーを持つことができます。ただし、ForeignKeyおよびRelatedManagerには複合キーのサポートがありません。結果として、複合主キーを持つモデルから関係をナビゲートすることはできません。
ディスカッション:
注-SqlAlchemyでは、以下で説明するようにこれが可能であり、SqlAlchemyを使用してDjangoのORMを置き換えることができます
外部キーは、 ForeignKeyConstraintオブジェクトを使用してテーブルレベルで定義することもできます。このオブジェクトは、単一列または複数列の外部キーを記述できます。複数列の外部キーは複合外部キーと呼ばれ、ほとんどの場合、複合主キーを持つテーブルを参照します。以下に、複合主キーを持つテーブル請求書を定義します。
invoice = Table('invoice', metadata,
Column('invoice_id', Integer, primary_key=True),
Column('ref_num', Integer, primary_key=True),
Column('description', String(60), nullable=False)
)
次に、請求書を参照する複合外部キーを持つテーブルinvoice_item:
invoice_item = Table('invoice_item', metadata,
Column('item_id', Integer, primary_key=True),
Column('item_name', String(60), nullable=False),
Column('invoice_id', Integer, nullable=False),
Column('ref_num', Integer, nullable=False),
ForeignKeyConstraint(['invoice_id', 'ref_num'], ['invoice.invoice_id', 'invoice.ref_num'])
)
はい、可能ですが、複数列の制約、つまり外部キーまたは主キーを使用する場合は、複合キーを作成する必要があります。例えば:
CREATE TABLE Student (
S_num INTEGER,
S_Cate INTEGER,
S_descr CHAR(200),
PRIMARY KEY (S_num, S_Cate))
CREATE TABLE sub_Student (
Ssub_ID INTEGER PRIMARY KEY,
Sref_num INTEGER,
Sref_Cate INTEGER,
sub_descr CHAR(500),
FOREIGN KEY (Sref_num, Sref_Cate) REFERENCES Student
(S_num, S_Cate))
とにかく、次のような「Djangoフィクスチャ」を作成できます。
CREATE INDEX product_category_id_id ON product (category_id, id);
これを行うには、モデルが存在product.sql
するサブフォルダーに名前が付けられたファイルを作成する必要があります。sql
フィクスチャは初期syncdbにロードされます。
@ pratik-mandrekarの答えは素晴らしいですが、適切な複数列の主キーがなくても、それを指摘したいと思います。djangoは、複数列の外部キーにまたがるクエリに対応できます。これは、変更が許可されていないスキーマのレガシーデータベースに基づく例です。
与えられた:
from django.db import models
class Account(models.Model):
# Collectively, location_no and occupant_no function as the primary key for Account.
location_no = models.IntegerField()
occupant_no = models.SmallIntegerField()
name = models.CharField(max_length=100)
class Meta:
managed = False
db_table = 'csracct'
unique_together = (('location_no', 'occupant_no'),)
class Call(models.Model):
call_id = models.IntegerField(primary_key=True)
# Collectively, location_no and occupant_no act as a foreign key to Account.
location_no = models.IntegerField()
occupant_no = models.SmallIntegerField()
notes = models.TextField()
class Meta:
managed = False
db_table = 'csrcall'
extra()
'steve'という名前のアカウントに対する最近の10件の呼び出しを取得するために使用する方法は次のとおりです。
calls = Call.extra(
tables = ['csracct'],
where = [
'csracct.location_no=csrcall.location_no',
'csracct.occupant_no=csrcall.occupant_no',
'csracct.name=%s',
],
params = ['steve'],
).order_by('-call_id')[:10]
これは最も洗練されたソリューションではありませんがextra()
、djangoの基本クエリセットツールキットの一部です。そのため、残りのdjangoコードとうまく連携します。order_byを実行し、通常のdjangoメソッドを使用してクエリセットを制限/スライスする方法に注目してください。