Django inspectdb 不尊重两列上的主键(postgres)

Django inspectdb not respecting primary key on two columns (postgres)

我正在使用 Django 连接到现有的 Postgres 数据库,使用 inspectdb 生成我的 models.py 文件。 Postgres 中的 tables 是这样创建的:

CREATE TABLE "a"
(
  "id" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'::uuid,
  CONSTRAINT "PK.a" PRIMARY KEY ("id")
)
CREATE TABLE "c"
(
  "id" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'::uuid,
  CONSTRAINT "PK.c" PRIMARY KEY ("id")
)
CREATE TABLE "b"
(
  "aid" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'::uuid,
  "cid" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'::uuid,
 CONSTRAINT "PK.b" PRIMARY KEY ("aid","cid"),
 CONSTRAINT "FK_a" FOREIGN KEY ("aid")
      REFERENCES "a" ("id") MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE,
 CONSTRAINT "FK_c" FOREIGN KEY ("cid")
      REFERENCES "c" ("id") MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE
)

然后我 运行 python manage.py inspectdb --database primary > models_test.py,结果是 models_test.py

class A(models.Model):
    id = models.UUIDField(primary_key=True)

    class Meta:
        managed = False
        db_table = 'a'


class B(models.Model):
    aid = models.OneToOneField(A, models.DO_NOTHING, db_column='aid', primary_key=True)
    cid = models.ForeignKey('C', models.DO_NOTHING, db_column='cid')

    class Meta:
        managed = False
        db_table = 'b'
        unique_together = (('aid', 'cid'),)


class C(models.Model):
    id = models.UUIDField(primary_key=True)

    class Meta:
        managed = False
        db_table = 'c'

注意 aid 上定义的 OneToOneField。

如果我改为创建 table b 为:

CREATE TABLE "b"
(
  "aid" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'::uuid,
  "cid" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'::uuid,
 CONSTRAINT "PK.b" PRIMARY KEY ("cid","aid"),
 CONSTRAINT "FK_a" FOREIGN KEY ("aid")
      REFERENCES "a" ("id") MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE,
 CONSTRAINT "FK_c" FOREIGN KEY ("cid")
      REFERENCES "c" ("id") MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE
)

然后重新运行 inspectdb 我得到以下输出:

class A(models.Model):
    id = models.UUIDField(primary_key=True)

    class Meta:
        managed = False
        db_table = 'a'


class B(models.Model):
    aid = models.ForeignKey(A, models.DO_NOTHING, db_column='aid')
    cid = models.OneToOneField('C', models.DO_NOTHING, db_column='cid', primary_key=True)

    class Meta:
        managed = False
        db_table = 'b'
        unique_together = (('cid', 'aid'),)


class C(models.Model):
    id = models.UUIDField(primary_key=True)

    class Meta:
        managed = False
        db_table = 'c'

注意 OneToOneField 现在在 cid 上。我怀疑这是一个错误,但我没有经验所以想在报告之前在这里问一下。 第二个问题:如果这是一个错误,是否值得报告?也许数据库设计很差或不常见?

I suspect this is a bug, but I am inexperienced so wanted to ask here before reporting.

不是真的。 Django 不适用于跨越两列或更多列的主键,或者至少在撰写本文时如此。它已被请求,例如 ticket #373,但设计者决定将其设置为 "wontfix"。

documentation进一步解释了这一点:

Do Django models support multiple-column primary keys?

No. Only single-column primary keys are supported.

But this isn’t an issue in practice, because there’s nothing stopping you from adding other constraints (using the unique_together model option or creating the constraint directly in your database), and enforcing the uniqueness at that level. Single-column primary keys are needed for things such as the admin interface to work; e.g., you need a single value to specify an object to edit or delete.

您可能在(不久的)将来无法做到这一点,因为很多 Django 工具都是在假设主键是 "scalar" 个实体的情况下构建的。

因此您可能应该稍微重新设计现有的数据库,然后尝试 运行 inspectdb