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

Djangoは複合主キーをサポートしていないので、何がその問題を克服するための最善の解決策でしょうか?注意:それは従来のデータベーステーブルであり、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

追加残念ながら、Djangoはnot yet have a composite primary keyを行います(複合主キーは、マルチ列の主キーと呼ばれている)

サードパーティのライブラリがあり、当然django-compositekeyそれに名前を付けます複数列の主キーを持つモデルを作成することができます。しかし、そのプロジェクトは現在維持されており、djangoの最新バージョンと互換性がありません。

あなたの最善の賭けは、あなたのテーブルに新しいフィールドを追加してそれを新しい主キーにすることです。現時点でプライマリキーを構成するフィールドには、unique_togetherというマークを付けることができます。これは理想的にはいくつかのクエリではないかもしれませんが。ほとんどの場合、十分です。

質問を現在のテーブル構造(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フラグを削除するだけでSQL含み、最も簡単です。

脚注:
例えばsqliteのようないくつかのデータベースはCREATE TABLELIKE句をサポートしていません。このような場合は、元のテーブルのcreate tableステートメントを検索し、テーブル名を編集した後にコピーをコピーする必要があります。あなたのテーブル構造で判断すると、mysqlを使用しているように見え、それはLIKE節をサポートしています。

+0

「純粋なSQL」ですか?私は 'CREATE TABLE'の' LIKE'が標準SQLだとは思っていません。おそらく純粋なMySQLに変更を加えたりするのでしょうか?(MySQL/MyISAMはLIKEをサポートしていますが、Firebirdは他のエンジン/ RDMBSについてはわかりません) –

+0

@JanSegreあなたはそれがすべてのデータベースでサポートされているとは限りません。私が上記の答えで純粋なSQLを書いていたとき、私は単にansiの標準ではなくdjangoと関係していないと考えていました。私の答えを更新する。 – e4c5

0

テーブルを編集できるようにするには、モデルからmanaged = Falseコマンドを削除する必要があります。

関連する問題