简体   繁体   English

django中的复合主键

[英]Composite primary key in django

I have a legacy db table which has composite primary key.我有一个具有复合主键的旧数据库表。 I don't think I will be able to change the structure to include a surrogate key, as there is some code written that uses that table.我认为我无法更改结构以包含代理键,因为编写了一些使用该表的代码。 And in django, I cannot use that table, as it doesn't have a primary key(non-composite).在 Django 中,我无法使用该表,因为它没有主键(非复合键)。

Do django models support composite primary keys? django 模型是否支持复合主键? If not, is there any workaround without changing the structure of the table?如果没有,是否有任何解决方法而不更改表的结构?

PS I am using postgresql. PS我正在使用postgresql。

Try similar below code:尝试类似下面的代码:

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

    key1 = models.IntegerField(primary_key=True)
    key2 = models.IntegerField()

or if you want only unique mixed fields:或者如果您只想要唯一的混合字段:

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

    key1 = models.IntegerField()
    key2 = models.IntegerField()

EDIT: I would like to note that there is a problem with this approach if there are 3 columns.编辑:我想指出,如果有 3 列,则这种方法存在问题。 Update queries don't work because it tries to update (puts pk fields right after "SET") the fields that are unique together and obviously fails.更新查询不起作用,因为它试图更新(将 pk 字段放在“SET”之后)唯一的字段,但显然失败了。

The accepted answer is fine.接受的答案很好。 However, it's a little old.然而,它有点老了。 unique_together may be deprecated in favor of UniqueConstraint . unique_together可能会被弃用,以支持UniqueConstraint So, the better way of doing this would be;因此,这样做的更好方法是;

UniqueConstraint(fields = ['key1', 'key2'], name = 'constraint_name')

I solved this with virtual field inherited from django AutoField, that combines a values from several fields into single JSON dict.我使用从 django AutoField 继承的虚拟字段解决了这个问题,它将来自多个字段的值组合到单个 JSON dict 中。

That makes such models, compatible with django admin and genetic views.这使得这些模型与 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)

This makes possible to access as to legacy databases , as to PostgreSQL TimeScaleDB tables这使得访问旧数据库PostgreSQL TimeScaleDB表成为可能

Another option is to set managed=False in the model's Meta , then manually create the table.另一种选择是在模型的Meta设置managed=False ,然后手动创建表。

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

In a postgres shell:在 postgres 外壳中:

CREATE TABLE myapp_mytable (
    foo INTEGER NOT NULL,
    bar INTEGER NOT NULL,
    baz INTEGER NOT NULL,
    PRIMARY KEY(foo, bar, baz)
);

It appears to behave correctly:它似乎行为正确:

>>> 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.

Note that this is only tested in Django 3.x, so I'm not sure if it works in older versions.请注意,这仅在 Django 3.x 中进行了测试,因此我不确定它是否适用于旧版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM