django中的复合主键

kha*_*vah 36 python django postgresql

我有一个遗留的db表,它有复合主键.我不认为我能够更改结构以包含代理键,因为有一些代码使用该表编写.在django中,我不能使用该表,因为它没有主键(非复合).

django模型是否支持复合主键?如果没有,是否有任何解决方法而不改变表的结构?

PS我正在使用postgresql.

M.j*_*vid 48

尝试类似下面的代码:

class MyTable(models.Model):
    class Meta:
        unique_together = (('key1', 'key2'),)

    key1 = models.IntegerField(primary_key=True)
    key2 = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

或者如果您只想要唯一的混合字段:

class MyTable(models.Model):
    class Meta:
        unique_together = (('key1', 'key2'),)

    key1 = models.IntegerField()
    key2 = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

编辑:我想注意,如果有3列,这种方法有问题.更新查询不起作用,因为它尝试更新(在"SET"之后放置pk字段)一起是唯一的字段并且明显失败.

  • 阅读本页:https://code.djangoproject.com/wiki/MultipleColumnPrimaryKeys (4认同)
  • 我的意思是,当你创建 `key2 = models.IntegerField(unique=True)` 时,难道不应该暗示 `key2` 对于所有值必须是唯一的,而不仅仅是单个 `key1` 吗? (3认同)
  • 请注意,第一个建议“不”等同于拥有复合主键,因为在“key1”上设置“primary_key = True”使其唯一,这意味着您将无法添加“(”的新组合key1, key2)` 如果“key1”的值已存在于表中。复合主键是关于字段的唯一_组合_。第二种建议可行,但它不会阻止 Django 自动创建“id”列。顺便说一下,这是一个[*15年前的问题*](https://code.djangoproject.com/ticket/373)! (3认同)
  • 有一个建议编辑说如下:我想要注意,如果有3列,这种方法有问题.更新查询不起作用,因为它尝试更新(在"SET"之后放置pk字段)一起是唯一的字段并且明显失败. (2认同)

Tec*_*ins 15

接受的答案很好。然而,它有点老了。unique_together可能会被弃用而支持UniqueConstraint。因此,这样做的更好方法是;

UniqueConstraint(fields = ['key1', 'key2'], name = 'constraint_name')
Run Code Online (Sandbox Code Playgroud)

  • 接受的答案提到您最多只能使用 2 个字段作为复合键及其代码 - 这会随着您的代码而改变吗? (2认同)

Rei*_*ica 9

managed=False另一种选择是在模型的 中设置Meta,然后手动创建表。

class MyTable(models.Model):
    foo = models.IntegerField(primary_key=True)
    bar = models.IntegerField()
    baz = models.IntegerField()

    class Meta:
        managed = False
        db_table = 'myapp_mytable'

    def __repr__(self):
        return f'<MyTable: MyTable object ({self.foo}, {self.bar}, {self.baz)>'
Run Code Online (Sandbox Code Playgroud)

在 postgres shell 中:

CREATE TABLE myapp_mytable (
    foo INTEGER NOT NULL,
    bar INTEGER NOT NULL,
    baz INTEGER NOT NULL,
    PRIMARY KEY(foo, bar, baz)
);
Run Code Online (Sandbox Code Playgroud)

它似乎表现正确:

>>> MyTable.objects.create(foo=1, bar=1, baz=1)
<MyTable: MyTable object (1, 1, 1)>

>>> MyTable.objects.create(foo=1, bar=1, baz=2)
<MyTable: MyTable object (1, 1, 2)>

>>> MyTable.objects.create(foo=1, bar=1, baz=2)
django.db.utils.IntegrityError: duplicate key value violates unique constraint "myapp_mytable_pkey"
DETAIL:  Key (foo, bar, baz)=(1, 1, 2) already exists.
Run Code Online (Sandbox Code Playgroud)

请注意,这仅在 Django 3.x 中进行了测试,因此我不确定它是否适用于旧版本。


kmm*_*vnr 5

我使用从 django AutoField 继承的虚拟字段解决了这个问题,它将来自多个字段的值组合到单个 JSON dict 中。

这使得这些模型与 django 管理和遗传视图兼容。

$ pip install django-viewflow --pre

from viewflow.fields import CompositeKey

class Seat(models.Model):
    id = CompositeKey(columns=['aircraft_code', 'seat_no'])
    aircraft_code = models.ForeignKey(
        Aircraft, models.DO_NOTHING,
        db_column='aircraft_code'
    )
    seat_no = models.CharField(max_length=4)
Run Code Online (Sandbox Code Playgroud)

这使得访问旧数据库PostgreSQL TimeScaleDB表成为可能