5

У меня есть устаревшая база данных, где в некоторой таблице содержится составной первичный ключ. Модель, которую я получаю при запуске команды manage.py inspectdb, выглядит следующим образом.Работа с составным первичным ключом в проекте django с устаревшей базой данных

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

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

EDIT: добавляет структурировать наследство табличных

+------------+------------+------+-----+---------+-------+ 
| 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  |  | 
+------------+------------+------+-----+---------+-------+ 
+0

Было бы лучше, если вы добавите структуру таблицы, а также. – e4c5

+0

@ e4c5 добавил устаревшую структуру таблицы – AmirM

ответ

1

К сожалению Джанго делает not yet have a composite primary key (составные первичные ключи также называются мультями ключей столбца первичных)

Существует библиотека третьей стороны, неудивительно назвать django-compositekey что позволяет создать модель с многоколоночным первичным ключом. Однако этот проект теперь поддерживается и несовместим с последними версиями django.

Лучше всего добавить новый столбец в свою таблицу, который является AutoField и сделать его новым первичным ключом. Поля, которые составляют первичный ключ в настоящее время, могут быть отмечены как unique_together. Хотя это может быть не идеально для нескольких запросов. Этого достаточно для большинства.

Если вы обновите свой вопрос с помощью текущей структуры таблицы (как показано на вашей консоли sql), я обновлю свой ответ, чтобы показать, как будет выглядеть модель.

Update Есть много различных способов, которыми вы можете удалить старую составной первичный ключ и заменить его новым авто приращения первичного ключа. Вот самый простой, она включает в себя только 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 не поддерживает пункт в CREATE TABLELIKE. В этих случаях вам придется искать инструкцию create table для исходной таблицы и скопировать вставку после редактирования имени таблицы. Судя по вашей структуре таблицы, вы, кажется, используете mysql, и она поддерживает предложение LIKE.

+0

Действительно ли это «чистый SQL»? Я не уверен, что 'LIKE' в' CREATE TABLE' является стандартным SQL, возможно, добавляет изменения в 'pure MySQL' или что-то в этом роде?(MySQL/MyISAM поддерживает LIKE, но Firebird этого не делает, не уверен в отношении других движков/RDMBS) –

+0

@JanSegre вы правы, что не поддерживаются всеми базами данных. Когда я писал чистый sql в вышеприведенном ответе, я просто думал не о том, чтобы задействовать django nd не стандарта ansi. Обновление моего ответа. – e4c5

0

Вы должны удалить удалось = False команду из модели, чтобы иметь возможность редактировать вашу таблицу