使用遗留数据库在django项目中使用复合主键

时间:2023-01-24 11:28:51

I have a legacy database, where some table contains composite primary key. The model I get by running manage.py inspectdb command looks like this.

我有一个遗留数据库,其中一些表包含复合主键。我通过运行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'),)

I can fetch data normally. However, the problem arises when I want to run save() command on some model instance. The query django executes is not correct one. For example:

我可以正常获取数据。但是,当我想在某个模型实例上运行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'}

But I need:

但是我需要:

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

Since django does not support composite primary key, what would be the best solution to overcome that problem? Note, it's legacy database table and it didn't have AutoField.

由于django不支持复合主键,因此克服该问题的最佳解决方案是什么?注意,它是遗留数据库表,它没有AutoField。

EDIT: adds legacy table structure

编辑:添加遗留表结构

+------------+------------+------+-----+---------+-------+
| 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 个解决方案

#1


2  

Unfortunately django does not yet have a composite primary key (composite primary keys are also called multi column primary keys)

不幸的是,django还没有复合主键(复合主键也称为多列主键)

There is a third party library, unsurprisingly name django-compositekey that makes it possible to create a model that has a multi column primary key. However that project is now maintained and not compatible with the latest versions of django.

有一个第三方库,不出所料地命名为django-compositekey,可以创建一个具有多列主键的模型。但是,该项目现在已经维护,并且与最新版本的django不兼容。

Your best bet, is to add a new column into your table which is a an AutoField and make it the new primary key. The fields that make up the primary key at present can then be marked as unique_together. While this may not be ideally for a few queries. It's good enough for most.

最好的办法是在表中添加一个新列,这是一个AutoField,并使其成为新的主键。然后,构成主键的字段可以标记为unique_together。虽然这可能不是一些查询的理想选择。这对大多数人来说已经足够了。

If you update your question with the current table structure (as shown in your sql console) I will update my answer to show what the model will look like.

如果您使用当前的表结构更新您的问题(如您的SQL控制台中所示),我将更新我的答案以显示模型的外观。

Update There are lots of different ways in which you can drop the old composite primary key and replace it with a new auto increment primary key. Here is the easiest, it involves just 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;

Then edit your model and remove the primary_key=True flag from those fields.

然后编辑模型并从这些字段中删除primary_key = True标志。

Footnote:
Some databases like sqlite for example does not support the LIKE clause in a CREATE TABLE. In these cases, you will have to look up the create table statement for the original table, and copy paste after editing the table name. Judging by your table structure you seem to be using mysql and it supports the LIKE clause.

脚注:例如sqlite等一些数据库不支持CREATE TABLE中的LIKE子句。在这些情况下,您必须查找原始表的create table语句,并在编辑表名后复制粘贴。根据您的表结构判断,您似乎使用的是mysql,它支持LIKE子句。

#2


0  

You must Delete managed = False command from the model to be able to edit your table

您必须从模型中删除managed = False命令才能编辑表

#1


2  

Unfortunately django does not yet have a composite primary key (composite primary keys are also called multi column primary keys)

不幸的是,django还没有复合主键(复合主键也称为多列主键)

There is a third party library, unsurprisingly name django-compositekey that makes it possible to create a model that has a multi column primary key. However that project is now maintained and not compatible with the latest versions of django.

有一个第三方库,不出所料地命名为django-compositekey,可以创建一个具有多列主键的模型。但是,该项目现在已经维护,并且与最新版本的django不兼容。

Your best bet, is to add a new column into your table which is a an AutoField and make it the new primary key. The fields that make up the primary key at present can then be marked as unique_together. While this may not be ideally for a few queries. It's good enough for most.

最好的办法是在表中添加一个新列,这是一个AutoField,并使其成为新的主键。然后,构成主键的字段可以标记为unique_together。虽然这可能不是一些查询的理想选择。这对大多数人来说已经足够了。

If you update your question with the current table structure (as shown in your sql console) I will update my answer to show what the model will look like.

如果您使用当前的表结构更新您的问题(如您的SQL控制台中所示),我将更新我的答案以显示模型的外观。

Update There are lots of different ways in which you can drop the old composite primary key and replace it with a new auto increment primary key. Here is the easiest, it involves just 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;

Then edit your model and remove the primary_key=True flag from those fields.

然后编辑模型并从这些字段中删除primary_key = True标志。

Footnote:
Some databases like sqlite for example does not support the LIKE clause in a CREATE TABLE. In these cases, you will have to look up the create table statement for the original table, and copy paste after editing the table name. Judging by your table structure you seem to be using mysql and it supports the LIKE clause.

脚注:例如sqlite等一些数据库不支持CREATE TABLE中的LIKE子句。在这些情况下,您必须查找原始表的create table语句,并在编辑表名后复制粘贴。根据您的表结构判断,您似乎使用的是mysql,它支持LIKE子句。

#2


0  

You must Delete managed = False command from the model to be able to edit your table

您必须从模型中删除managed = False命令才能编辑表