5

Ho un database precedente, in cui alcune tabelle contengono una chiave primaria composita. Il modello che ottengo eseguendo il comando manage.py inspectdb ha questo aspetto.Utilizzo della chiave primaria composita nel progetto django con database legacy

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

Posso recuperare i dati normalmente. Tuttavia, il problema sorge quando voglio eseguire il comando save() su qualche istanza di modello. La query eseguita da django non è corretta. Per esempio:

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

Ma ho bisogno:

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

Dato Django non supporta chiave primaria composta, quale sarebbe la soluzione migliore per superare questo problema? Nota, è una tabella di database legacy e non aveva AutoField.

EDIT: aggiunge la struttura delle tabelle eredità

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

Sarebbe meglio se si aggiunge la struttura della tabella pure. – e4c5

+0

@ e4c5 ha aggiunto la struttura della tabella legacy – AmirM

risposta

1

Purtroppo Django fa not yet have a composite primary key (chiavi primarie composite sono chiamati anche a più chiavi colonna primaria)

C'è una libreria di terze parti, ovviamente citarne django-compositekey che rende possibile creare un modello che ha una chiave primaria multi colonna. Comunque quel progetto è ora mantenuto e non compatibile con le ultime versioni di Django.

La soluzione migliore è aggiungere una nuova colonna nella tabella che è un campo automatico e trasformarla nella nuova chiave primaria. I campi che costituiscono la chiave primaria attualmente possono quindi essere contrassegnati come unique_together. Anche se questo potrebbe non essere ideale per alcune domande. È abbastanza buono per la maggior parte.

Se si aggiorna la domanda con la struttura della tabella corrente (come mostrato nella console sql) aggiornerò la mia risposta per mostrare come sarà il modello.

Aggiornamento Ci sono molti modi diversi in cui si può cadere la vecchia chiave primaria composta e sostituirla con una nuova chiave primaria incremento automatico. Qui è il più facile, si tratta solo di 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; 

quindi modificare il proprio modello e rimuovere il primary_key = True bandiera da quei campi.

Nota:
Alcuni database SQLite, come ad esempio non supporta la clausola LIKE in un CREATE TABLE. In questi casi, dovrai cercare l'istruzione table create per la tabella originale e copiare paste dopo aver modificato il nome della tabella. A giudicare dalla struttura della tabella sembra che tu stia usando mysql e supporta la clausola LIKE.

+0

Si tratta di 'puro SQL'? Non sono sicuro che 'LIKE' in' CREATE TABLE' sia SQL standard, forse aggiungo modifiche a 'pure MySQL' o qualcosa del genere?(MySQL/MyISAM supporta LIKE ma Firebird no, non sono sicuro di altri motori/RDMBS) –

+0

@JanSegre hai ragione che non è supportato da tutti i database. Quando stavo scrivendo sql puro nella risposta di cui sopra, stavo semplicemente pensando di non coinvolgere django e non dello standard ansi. Aggiornamento della mia risposta. – e4c5

0

è necessario eliminare riuscito = False comando dal modello di essere in grado di modificare la tabella di