Как реализовать многозначный атрибут в Django?

У меня есть устаревшая база данных со следующими таблицами:

человек

person_id (PK)  |  first_name  |  last_name
        1       |  John        |  Doe
        2       |  David       |  Bentley

телефонные номера

person_id (FK,PK) |  phone_number (PK)  | area_code (PK)
        1         |  758-4551           | 909
        1         |  763-3445           | 909
        2         |  634-0011           | 637

У каждого человека может быть ноль или более телефонных номеров, что является многозначным атрибутом сущности человека.

Я попытался использовать команду Django inspectdb, которая сгенерировала следующие models.py:

class Person(models.Model):
    person_id = models.BigIntegerField(primary_key=True)
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)

    class Meta:
        managed = False
        db_table = 'person'


class PhoneNumbers(models.Model):
    person = models.ForeignKey(Person, models.DO_NOTHING)
    phone_number = models.CharField(max_length=15)
    area_code = models.CharField(max_length=15)

    class Meta:
        managed = False
        db_table = 'phonenumbers'
        unique_together = (('person', 'phone_number', 'area_code'),)

Однако, когда я попытался сохранить новый экземпляр PhoneNumbers, Django вернул следующее сообщение об ошибке:

django.db.utils.ProgrammingError: column phonenumbers.id does not exist

Очевидно, Джанго ожидает, что в таблице телефонных номеров будет суррогатный ключ. Поскольку таблица телефонных номеров не является сущностью, у нее нет суррогатного ключа в моей устаревшей базе данных. Обратите внимание, что первичный ключ таблицы phonenumbers представляет собой композицию всех ее столбцов.

Как я могу сопоставить эти таблицы с моделями Django, чтобы они работали с моей старой базой данных?


person Peter LT    schedule 08.06.2016    source источник


Ответы (2)


Django не поддерживает составные первичные ключи, и ваша таблица PhoneNumbers имеет первичный ключ, который охватывает три столбца. Этот тикет был открыт уже много лет. Существует сторонний плагин, который обеспечивает поддержку составного первичного ключа, но он не поддерживается уже два года и несовместим. с последними версиями Django.

Решение состоит в том, чтобы добавить первичный ключ. Но перед этим сделать

./manage.py migrate

Это гарантирует, что таблицы, необходимые django, будут созданы в вашей устаревшей базе данных.

Теперь измените свои модели, чтобы удалить эту строку

managed = False

Это сигнализирует django, что изменения в моделях должны быть отражены в базе данных. Затем измените свою модель следующим образом.

class Person(models.Model):
    id = models.BigIntegerField(primary_key=True, db_column='person_id')
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)

    class Meta:
        db_table = 'person'


class PhoneNumbers(models.Model):
    id = models.BigIntegerField(primary_key=True)
    person = models.ForeignKey(Person, models.DO_NOTHING)
    phone_number = models.CharField(max_length=15)
    area_code = models.CharField(max_length=15)

    class Meta:
        db_table = 'phonenumbers'
        unique_together = (('person', 'phone_number', 'area_code'),)

Тогда сделайте

 ./manage.py makemigrations  your_app_name
 ./manage.py migrate

Обратите внимание, что я переименовал поле первичного ключа в Person. Это просто косметическое изменение. Это потому, что по соглашению поле первичного ключа должно быть идентификатором. Когда вы имеете дело с большим количеством моделей, вы, вероятно, забудете, что первичный ключ этой модели был назван по-разному. Отсюда и изменение.

person e4c5    schedule 09.06.2016

В Django все модели (написанные для вас или сгенерированные с помощью inspectdb) должен иметь первичный ключ.

Если вы хотите использовать таблицу phonenumbers в качестве модели, вам потребуется, чтобы эта таблица имела первичный ключ.

В этом случае я советую вам изменить свою устаревшую таблицу, чтобы вручную добавить новый первичный ключ и отказаться от составного первичного ключа. Ваша устаревшая таблица имеет составной первичный ключ (номер_телефона+код_города), который официально не поддерживается в Django.

person Yonsy Solis    schedule 08.06.2016