Работа с составным первичным ключом в проекте django с устаревшей базой данных
У меня есть устаревшая база данных, где некоторые таблицы содержат составной первичный ключ. Модель, которую я получаю, запустив manage.py inspectdb
Команда выглядит так.
class MyTable(models.Model):
field1_id = models.IntegerField(db_column='field1id', primary_key=True)
is_favorite = models.BooleanField(db_column='isfavorite', default=False, null=False)
is_admin = models.BooleanField(db_column='isadmin', default=False, null=False)
role = models.IntegerField(default=USER_GUEST, null=False)
field2 = models.BooleanField(null=False, default=True)
field3 = models.BooleanField(null=False, default=True)
is_active = models.BooleanField(db_column='isactive', null=False, default=True)
user = models.ForeignKey(
CustomUser, models.DO_NOTHING, db_column='userid', primary_key=True)
class Meta:
managed = False
db_table = 'mytable'
unique_together = (('user', 'field1_id'),)
Я могу получить данные в обычном режиме. Однако проблема возникает, когда я хочу запустить save()
Команда на некотором экземпляре модели. Запрос django выполняется неверно. Например:
>>> from web_services.apps.my_app.models import MyTable
>>> g = MyTable.objects.get(field1_id=12)
>>> g.is_active = True
>>> g.save()
>>> connection.queries[-1]
{'time': '0.000', 'sql': 'UPDATE `mytable` SET `isfavorite` = 0, `isadmin` = 1, `role` = 3, `field2` = 1, `field3` = 1, `isactive` = 1 WHERE `mytable`.`field1id` = 12'}
Но мне нужно:
{'time': '0.000', 'sql': 'UPDATE `mytable` SET `isfavorite` = 0, `isadmin` = 1, `role` = 3, `field2` = 1, `field3` = 1, `isactive` = 1 WHERE `mytable`.`field1id` = 12' AND `mytable`.`userid` = 1'}
Поскольку django не поддерживает составной первичный ключ, каково будет лучшее решение для преодоления этой проблемы? Обратите внимание, это устаревшая таблица базы данных, и она не имела AutoField
,
РЕДАКТИРОВАТЬ: добавляет устаревшую структуру таблицы
+------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------+------+-----+---------+-------+
| userid | int(11) | NO | PRI | NULL | |
| field1id | int(11) | NO | PRI | NULL | |
| isfavorite | int(11) | NO | | 0 | |
| isadmin | int(11) | NO | | 0 | |
| role | int(11) | YES | | NULL | |
| field2 | tinyint(1) | NO | | 1 | |
| field3 | tinyint(1) | NO | | 1 | |
| isactive | tinyint(4) | NO | | 1 | |
+------------+------------+------+-----+---------+-------+
2 ответа
К сожалению, у django еще нет составного первичного ключа (составные первичные ключи также называются многоколоночными первичными ключами)
Существует сторонняя библиотека, неудивительно, что она называется django-композитный ключ, что позволяет создавать модель с первичным ключом из нескольких столбцов. Однако этот проект сейчас поддерживается и не совместим с последними версиями django.
Лучше всего добавить в вашу таблицу новый столбец, который представляет собой автоматическое поле, и сделать его новым первичным ключом. Поля, которые в настоящее время составляют первичный ключ, могут быть помечены как уникальные. Хотя это не может быть идеально для нескольких запросов. Это достаточно хорошо для большинства.
Если вы обновите свой вопрос с использованием текущей структуры таблицы (как показано в консоли SQL), я обновлю свой ответ, чтобы показать, как будет выглядеть модель.
Обновление Существует много разных способов, которыми вы можете удалить старый составной первичный ключ и заменить его новым первичным ключом с автоматическим приращением. Здесь самое простое, в нем задействован только SQL
CREATE TABLE newtable LIKE mytable;
ALTER TABLE newtable DROP PRIMARY KEY;
ALTER TABLE newtable ADD `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY;
RENAME TABLE mytable to mytable_old;
RENAME TABLE newtable to mytable;
INSERT INTO mytable(userid,field1id, rest of the fields)
SELECT * FROM mytable_old;
Затем отредактируйте вашу модель и удалите флаг primary_key=True из этих полей.
Сноска:
Например, некоторые базы данных, такие как sqlite, не поддерживают LIKE
пункт в CREATE TABLE
, В этих случаях вам придется искать оператор создания таблицы для исходной таблицы и копировать вставку после редактирования имени таблицы. Судя по структуре вашей таблицы, вы, похоже, используете mysql, и он поддерживает LIKE
пункт.
Вы должны удалить команду managed = False из модели, чтобы иметь возможность редактировать таблицу