5

Ich habe eine Legacy-Datenbank, in der einige Tabelle Composite-Primärschlüssel enthält. Das Modell, das ich bekomme, indem ich den Befehl manage.py inspectdb läuft, sieht so aus.Arbeiten mit Composite-Primärschlüssel in Django-Projekt mit Legacy-Datenbank

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'),) 

Ich kann Daten normal abrufen. Das Problem tritt jedoch auf, wenn ich den Befehl save() bei einer bestimmten Modellinstanz ausführen möchte. Die Abfrage, die django ausführt, ist nicht korrekt. Zum Beispiel:

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

Aber ich brauche:

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

Da django nicht zusammengesetzte Primärschlüssel nicht unterstützt, was die beste Lösung wäre, dieses Problem zu überwinden? Beachten Sie, es ist Legacy-Datenbanktabelle und es hatte keine AutoField.

EDIT: fügt Legacy-Tabellenstruktur

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

Es wäre am besten, wenn Sie die Tabellenstruktur als auch hinzufügen. – e4c5

+0

@ e4c5 hinzugefügt Legacy-Tabellenstruktur – AmirM

Antwort

1

Leider django hat not yet have a composite primary key (Composite Primärschlüssel sind auch mehrspaltige Primärschlüssel genannt)

Es gibt eine dritte Partei Bibliothek, wenig überraschend django-compositekey Namen ein, ermöglicht es, ein Modell mit einem mehrspaltigen Primärschlüssel zu erstellen. Dieses Projekt wird jedoch beibehalten und ist nicht kompatibel mit den neuesten Versionen von django.

Ihre beste Wette ist, eine neue Spalte in Ihrer Tabelle, die ein AutoField ist, hinzuzufügen und es zum neuen Primärschlüssel zu machen. Die Felder, aus denen der Primärschlüssel besteht, können dann als unique_together markiert werden. Dies ist möglicherweise nicht ideal für einige Abfragen. Es ist gut genug für die meisten.

Wenn Sie Ihre Frage mit der aktuellen Tabellenstruktur (wie in Ihrer SQL-Konsole angezeigt) aktualisieren, werde ich meine Antwort aktualisieren, um zu zeigen, wie das Modell aussehen wird.

Aktualisieren Es gibt viele verschiedene Möglichkeiten, wie Sie den alten zusammengesetzten Primärschlüssel löschen und durch einen neuen Primärschlüssel mit automatischem Zuwachs ersetzen können. Hier ist die einfachste, es geht nur 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; 

Dann wird Ihr Modell bearbeiten und das primary_key = True Flag aus diesen Bereichen entfernen.

Fußnote:
Einige Datenbanken wie SQLite zum Beispiel unterstützt nicht die LIKE-Klausel in einer CREATE TABLE. In diesen Fällen müssen Sie die Anweisung create table für die Originaltabelle suchen und nach dem Bearbeiten des Tabellennamens kopieren. Gemessen an Ihrer Tabellenstruktur scheinen Sie mysql zu verwenden und es unterstützt die Klausel LIKE.

+0

Ist es "reine SQL" obwohl? Ich bin mir nicht sicher, 'LIKE' in' CREATE TABLE' ist Standard-SQL, vielleicht eine Änderung zu 'pure MySQL' oder etwas ähnliches?(MySQL/MyISAM unterstützt LIKE aber Firebird nicht, nicht sicher über andere Engines/RDMBSs) –

+0

@JanSegre Sie haben Recht, dass es nicht von allen Datenbanken unterstützt wird. Als ich in der obigen Antwort reinen SQL schrieb, dachte ich nur daran, den Django nicht zu verwenden und nicht den Standard der ANSI. Aktualisierung meiner Antwort – e4c5

0

Sie müssen aus dem Modell = False Befehl verwaltet löschen kann, um Ihre Tabelle bearbeiten