10

是否可以在另一个模型中定义引用多列的外键?

例如,一个外键引用了产品表中的一个两列索引,SQL 语句:

FOREIGN KEY (product_category, product_id) REFERENCES product(category, id)

顺便说一句,我已经研究过django.contrib.contenttypes,认为这不是这种情况的完美解决方案。

4

4 回答 4

15

尚不支持。如果您愿意,有一张票和可能的处理方法。也许你甚至可以运行自定义 sql

多列主键支持

关系数据库设计使用一组列作为表的主键。当这个集合包含多个列时,它被称为“复合”或“复合”主键。(有关术语的更多信息,这里是一篇讨论数据库键的文章)。目前 Django 模型仅支持该集合中的单个列,拒绝了许多表的自然主键是多个列的设计。Django 目前不能使用这些模式;相反,他们必须引入一个冗余的单列键(“代理”键),迫使应用程序在任何给定实例中对表使用哪个键做出任意和不必要的选择。本页讨论如何让 Django 支持这些复合主键。有很多细节可以在这里得到,但做得对,

当前状态

当前状态是该问题已被接受/分配并正在处理中,在 http://github.com/dcramer/django-compositepks 有部分实现。该实现允许具有复合主键。但是,ForeignKey 和 RelatedManager 中缺少对复合键的支持。因此,无法从具有复合主键的模型中导航关系。

讨论:

大卫克莱默的初始补丁

复合外键API设计

注意 - SqlAlchemy允许这样做,如下所述,您可以使用 SqlAlchemy 替换 Django 的 ORM

也可以使用ForeignKeyConstraint对象在表级别定义外键。该对象可以描述单列或多列外键。多列外键称为复合外键,几乎总是引用具有复合主键的表。下面我们定义一个具有复合主键的表 invoice:

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'])
)

参考

于 2012-10-30T06:24:10.887 回答
0

无论如何,您可以像这样创建一个“Django 固定装置”:

CREATE INDEX product_category_id_id ON product (category_id, id);

为此,您必须在模型所在product.sql的子文件夹中创建一个名为的文件。sql夹具在初始同步数据库上加载。

于 2013-08-30T13:19:02.930 回答
0

是的,它可能,但是当您使用多列约束(即外键或主键)时,您需要创建一个复合键。例如:

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))
于 2012-11-06T05:40:20.357 回答
0

@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 代码的其余部分配合使用。请注意我们如何排序,并使用通常的 django 方法限制/切片查询集。

于 2021-02-25T19:41:05.427 回答