Composite primary keys — Django 6.0.4 documentation(2026)
创始人
2026-05-31 09:26:24
0
Django教程

Composite primary keys

New in Django 5.2.

In Django, each model has a primary key. By default, this primary key consists of a single field.

In most cases, a single primary key should suffice. In database design, however, defining a primary key consisting of multiple fields is sometimes necessary.

To use a composite primary key, when defining a model set the pk attribute to be a CompositePrimaryKey:

class Product(models.Model):
    name = models.CharField(max_length=100)


class Order(models.Model):
    reference = models.CharField(max_length=20, primary_key=True)


class OrderLineItem(models.Model):
    pk = models.CompositePrimaryKey("product_id", "order_id")
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    quantity = models.IntegerField()

This will instruct Django to create a composite primary key (PRIMARY KEY (product_id, order_id)) when creating the table.

A composite primary key is represented by a tuple:

>>> product = Product.objects.create(name="apple")
>>> order = Order.objects.create(reference="A755H")
>>> item = OrderLineItem.objects.create(product=product, order=order, quantity=1)
>>> item.pk
(1, "A755H")

You can assign a tuple to the pk attribute. This sets the associated field values:

>>> item = OrderLineItem(pk=(2, "B142C"))
>>> item.pk
(2, "B142C")
>>> item.product_id
2
>>> item.order_id
"B142C"

A composite primary key can also be filtered by a tuple:

>>> OrderLineItem.objects.filter(pk=(1, "A755H")).count()
1

We're still working on composite primary key support for relational fields, including GenericForeignKey fields, and the Django admin. Models with composite primary keys cannot be registered in the Django admin at this time. You can expect to see this in future releases.

Migrating to a composite primary key

Django doesn't support migrating to, or from, a composite primary key after the table is created. It also doesn't support adding or removing fields from the composite primary key.

If you would like to migrate an existing table from a single primary key to a composite primary key, follow your database backend's instructions to do so.

Once the composite primary key is in place, add the CompositePrimaryKey field to your model. This allows Django to recognize and handle the composite primary key appropriately.

While migration operations (e.g. AddField, AlterField) on primary key fields are not supported, makemigrations will still detect changes.

In order to avoid errors, it's recommended to apply such migrations with --fake.

Alternatively, SeparateDatabaseAndState may be used to execute the backend-specific migrations and Django-generated migrations in a single operation.

Composite primary keys and relations

Relationship fields, including generic relations do not support composite primary keys.

For example, given the OrderLineItem model, the following is not supported:

class Foo(models.Model):
    item = models.ForeignKey(OrderLineItem, on_delete=models.CASCADE)

Because ForeignKey currently cannot reference models with composite primary keys.

To work around this limitation, ForeignObject can be used as an alternative:

class Foo(models.Model):
    item_order_id = models.CharField(max_length=20)
    item_product_id = models.IntegerField()
    item = models.ForeignObject(
        OrderLineItem,
        on_delete=models.CASCADE,
        from_fields=("item_order_id", "item_product_id"),
        to_fields=("order_id", "product_id"),
    )

ForeignObject is much like ForeignKey, except that it doesn't create any columns (e.g. item_id), foreign key constraints or indexes in the database, and the on_delete argument is ignored.

Composite primary keys and database functions

Many database functions only accept a single expression.

MAX("order_id")  -- OK
MAX("product_id", "order_id")  -- ERROR

In these cases, providing a composite primary key reference raises a ValueError, since it is composed of multiple column expressions. An exception is made for Count.

Max("order_id")  # OK
Max("pk")  # ValueError
Count("pk")  # OK

Composite primary keys in forms

As a composite primary key is a virtual field, a field which doesn't represent a single database column, this field is excluded from ModelForms.

例如,采取以下表单:

class OrderLineItemForm(forms.ModelForm):
    class Meta:
        model = OrderLineItem
        fields = "__all__"

This form does not have a form field pk for the composite primary key:

>>> OrderLineItemForm()

Setting the primary composite field pk as a form field raises an unknown field FieldError.

Primary key fields are read only

If you change the value of a primary key on an existing object and then save it, a new object will be created alongside the old one (see Field.primary_key).

This is also true of composite primary keys. Hence, you may want to set Field.editable to False on all primary key fields to exclude them from ModelForms.

Composite primary keys in model validation

Since pk is only a virtual field, including pk as a field name in the exclude argument of Model.clean_fields() has no effect. To exclude the composite primary key fields from model validation, specify each field individually. Model.validate_unique() can still be called with exclude={"pk"} to skip uniqueness checks.

Building composite primary key ready applications

Prior to the introduction of composite primary keys, the single field composing the primary key of a model could be retrieved by introspecting the primary key attribute of its fields:

>>> pk_field = None
>>> for field in Product._meta.get_fields():
...     if field.primary_key:
...         pk_field = field
...         break
...
>>> pk_field

Now that a primary key can be composed of multiple fields the primary key attribute can no longer be relied upon to identify members of the primary key as it will be set to False to maintain the invariant that at most one field per model will have this attribute set to True:

>>> pk_fields = []
>>> for field in OrderLineItem._meta.get_fields():
...     if field.primary_key:
...         pk_fields.append(field)
...
>>> pk_fields
[]

In order to build application code that properly handles composite primary keys the _meta.pk_fields attribute should be used instead:

>>> Product._meta.pk_fields
[]
>>> OrderLineItem._meta.pk_fields
[
    ,
    
]

Last update:

4月 20, 2026


本文整理自 Django 6.0 官方中文文档,转载请注明出处。

相关内容

热门资讯

玻璃硬盘原理图 玻璃硬盘原理 玻璃硬盘,又称为磁头悬浮硬盘(Magnetic Head Flying Disk,MHFD),是一种...
闲鱼搜索规则与技巧 闲鱼最新特... 在闲鱼这个二手交易平台上,有很多用户都希望能够找到一些特殊的东西,比如一些罕见的收藏品、独特的手工艺...
家里监控最长能保存多少天的记录... 家里监控一般保存多久 随着科技的发展,家庭监控系统已经成为了许多家庭的必备设备,它不仅可以帮助我们...
华为tag有用吗 华为tag-... 华为Tag是华为手机中的一种功能,它可以帮助用户更好地管理自己的手机数据和应用,通过使用华为Tag,...
ps5手柄可用手机快充充电吗 ... PS5手柄,即PlayStation 5的DualSense手柄,是索尼公司为PlayStation...
QQ音乐提示代理模式可能无法正... QQ音乐提示代理模式可能无法正常访问,如上图所示,是怎么回事呢? 这个可能和你的网络设置有关系,首先...
收到微信有提示音怎么去掉 微信... 微信收到信息没有提示音,可能是由多种原因导致的,以下是一些可能的原因及解决方法: 1. 手机静音或...
a100显卡对应的cuda版本 在进行GPU加速的编程中,CUDA是常用的架构和平台,其版本和显卡型号之间存在着一定的对应关系。本篇...
别人打电话听不见我说话怎么回事... 当我们在使用手机时,可能会遇到别人打电话过来听不见声音的情况,这种情况可能是由多种原因导致的,下面我...
苹果手机非通讯录电话打不进来 ... 手机电话打不进来可能有多种原因,以下是一些常见的问题及解决方法: 1. **信号问题**: ...