Django inspectdb не соблюдает первичный ключ в двух столбцах (postgres) - PullRequest
1 голос
/ 16 февраля 2020

Я подключаюсь к существующей базе данных Postgres с помощью Django, используя inspectdb для создания моего файла models.py. Таблицы в Postgres были созданы следующим образом:

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'

обратите внимание на OneToOneField, определенный в aid.

Если я вместо этого создаю таблицу 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. Я подозреваю, что это ошибка, но я неопытный, поэтому хотел спросить здесь, прежде чем сообщать. Вторичный вопрос: если это ошибка, стоит ли сообщать? Может быть, дизайн базы данных очень плохой или необычный?

1 Ответ

0 голосов
/ 16 февраля 2020

Я подозреваю, что это ошибка, но я неопытный, поэтому хотел спросить здесь, прежде чем сообщать.

Не совсем. Django не работает с первичными ключами, которые охватывают два или более столбца или, по крайней мере, на момент написания. Это было запрошено, например, ticket # 373 , но дизайнеры решили установить это на "wontfix".

Документация дополнительно объясняет это:

Do Django модели поддерживают первичные ключи с несколькими столбцами ?

Поддерживаются только первичные ключи с одним столбцом.

Но на практике это не проблема, потому что ничто не мешает вам добавить другие ограничения (используя опцию модели unique_together или создать ограничение непосредственно в вашей базе данных) и обеспечить уникальность на этом уровне. Первичные ключи с одним столбцом необходимы для работы таких объектов, как интерфейс администратора; Например, вам нужно одно значение, чтобы указать объект для редактирования или удаления.

Скорее всего, вы не сможете сделать это в (ближайшем) будущем, так как многие инструменты Django построен с предположением, что первичные ключи являются «скалярными» сущностями.

Таким образом, вам, вероятно, следует немного изменить структуру существующей базы данных и попытаться запустить inspectdb после этого.

...