Il valore chiave duplicato di IntegrityError viola il vincolo univoco – django / postgres

Sto seguendo una domanda che ho chiesto prima in cui ho cercato di cercare una conversione da una query mysql goofy / mal scritta a postgresql. Credo di esserci riuscito. Ad ogni modo, sto usando i dati che sono stati spostati manualmente da un database mysql a un database postgres. Sto usando una query che sembra così:

""" UPDATE krypdos_coderound cru set is_correct = case when t.kv_values1 = t.kv_values2 then True else False end from (select cr.id, array_agg( case when kv1.code_round_id = cr.id then kv1.option_id else null end ) as kv_values1, array_agg( case when kv2.code_round_id = cr_m.id then kv2.option_id else null end ) as kv_values2 from krypdos_coderound cr join krypdos_value kv1 on kv1.code_round_id = cr.id join krypdos_coderound cr_m on cr_m.object_id=cr.object_id and cr_m.content_type_id =cr.content_type_id join krypdos_value kv2 on kv2.code_round_id = cr_m.id WHERE cr.is_master= False AND cr_m.is_master= True AND cr.object_id=%s AND cr.content_type_id=%s GROUP BY cr.id ) t where t.id = cru.id """ % ( self.object_id, self.content_type.id) ) 

Ho ragione di credere che funzioni bene. Tuttavia, questo ha portato a un nuovo problema. Quando provo a inviare, ricevo un errore da django che afferma:

 IntegrityError at (some url): duplicate key value violates unique constraint "krypdos_value_pkey" 

Ho esaminato molte delle risposte pubblicate qui e non ho ancora trovato la soluzione al mio problema (anche se le domande correlate sono state fatte per alcune letture interessanti). Lo vedo nei miei registri, che è interessante perché non ho mai chiamato esplicitamente insert- django deve gestirlo:

  STATEMENT: INSERT INTO "krypdos_value" ("code_round_id", "variable_id", "option_id", "confidence", "freetext") VALUES (1105935, 11, 55, NULL, E'') RETURNING "krypdos_value"."id" 

Tuttavia, provare a eseguire tali risultati nell’errore della chiave duplicata. L’errore effettivo viene generato nel codice qui sotto.

  # Delete current coding CodeRound.objects.filter(object_id=o.id,content_type=object_type,is_master=True).delete() code_round = CodeRound(object_id=o.id,content_type=object_type,coded_by=request.user,comments=request.POST.get('_comments',None),is_master=True) code_round.save() for key in request.POST.keys(): if key[0] != '_' or key != 'csrfmiddlewaretoken': options = request.POST.getlist(key) for option in options: Value(code_round=code_round,variable_id=key,option_id=option,confidence=request.POST.get('_confidence_'+key, None)).save() #This is where it dies # Resave to set is_correct code_round.save() o.status = '3' o.save( 

Ho controllato le sequenze e tali e sembrano essere in ordine. A questo punto non sono sicuro di cosa fare- presumo che sia qualcosa alla fine del django ma non ne sono sicuro. Qualsiasi feedback sarebbe molto apprezzato!

Questo è successo a me – si scopre che è necessario risincronizzare i campi chiave primaria in Postgres. La chiave è l’istruzione SQL:

 SELECT setval('tablename_id_seq', (SELECT MAX(id) FROM tablename)+1) 

Sembra essere una nota differenza di comportamento tra MySQL e SQLite (aggiornano la prossima chiave primaria disponibile anche quando si inserisce un object con un ID esplicito) backend e altri backend come Postgres, Oracle, … (non lo fanno) .

C’è un biglietto che descrive lo stesso problema . Anche se è stato chiuso come non valido, fornisce un suggerimento che esiste un comando di gestione Django per aggiornare la prossima chiave disponibile.

Per visualizzare l’SQL che aggiorna tutti i prossimi ID per l’applicazione MyApp :

 python manage.py sqlsequencereset MyApp 

Per poter eseguire l’istruzione, è ansible fornirla come input per il comando di gestione dbshell . Per bash, puoi digitare:

 python manage.py sqlsequencereset MyApp | python manage.py dbshell 

Il vantaggio dei comandi di gestione è che astrae il backend del DB sottostante, quindi funzionerà anche se successivamente si migrerà su un back-end diverso.

Oltre alla risposta zapphod:

Nel mio caso l’indicizzazione era davvero scorretta, dal momento che avevo cancellato tutte le migrazioni e il database probabilmente 10-15 volte quando si sviluppava perché non ero nella fase di migrazione di qualcosa.

Stavo ottenendo un IntegrityError su finished_product_template_finishedproduct_pkey

Reindicizzare la tabella e riavviare runserver:

Stavo usando pgadmin3 e per qualsiasi indice non fosse corretto e lanciando errori chiave duplicati ho navigato verso i constraints e reindicizzato.

inserisci la descrizione dell'immagine qui

E poi reindicizzato.

inserisci la descrizione dell'immagine qui

Se hai copiato manualmente i database, potresti riscontrare il problema descritto qui .

Ho avuto lo stesso problema. Avevo un tavolo esistente nella mia app “inventario” e volevo aggiungere nuovi record nell’amministratore di django e ho ricevuto questi messaggi:

Il valore chiave duplicato viola il vincolo univoco “inventory_part_pkey” DETAIL: Key (part_id) = (1) esiste già.

Come accennato prima di eseguire il codice qui sotto per ottenere generare un comando SQL per reimpostare l’id-s:

 python manage.py sqlsequencereset inventory 

Nel mio caso python manage.py sqlsequencereset MyApp | python manage.py dbshell python manage.py sqlsequencereset MyApp | python manage.py dbshell non funzionava

  • Così ho copiato l’istruzione SQL generata.
  • Quindi ho aperto pgAdmin per postgreSQL e ho aperto il mio db.
  • Cliccato sull’icona 6. (Esegui query SQL arbitrarie)
  • Copiato l’affermazione di ciò che è stato generato.

Nel mio caso è stato:

INIZIO; SELECT setval (pg_get_serial_sequence (‘”inventory_signup”‘, ‘id’), coalesce (max (“id”), 1), max (“id”) NON è null) FROM “inventory_signup”; SELECT setval (pg_get_serial_sequence (‘”inventory_supplier”‘, ‘id’), coalesce (max (“id”), 1), max (“id”) NON è null) FROM “inventory_supplier”; COMMETTERE;

L’ho eseguito con F5.

Ciò ha corretto tutti i miei tavoli e infine aggiunto nuovi record fino alla fine, non cercando più di aggiungerlo a id = 1.

Ho riscontrato questo errore perché stavo passando argomenti extra al metodo di salvataggio nel modo sbagliato.

Per chiunque incontri questo, prova a forzare UPDATE con:

 instance_name.save(..., force_update=True) 

Se ricevi un errore che non puoi passare force_insert e force_update allo stesso tempo, probabilmente stai passando alcuni argomenti personalizzati nel modo sbagliato, come ho fatto io.

La soluzione è che è necessario risincronizzare i campi chiave primaria come riportato da “Hacking Life” che ha scritto un codice SQL di esempio ma, come suggerito da “Ad N” è meglio eseguire il comando sqlsequencereset per ottenere il codice SQL esatto che può copiare e incollare o eseguire con un altro comando.

Come ulteriore miglioramento a queste risposte suggerirei a te e agli altri lettori di non copiare e incollare il codice SQL ma, in modo più sicuro, di eseguire la query SQL generata da sqlsequencereset dal tuo codice python in questo modo ( usando il database predefinito ):

 from django.core.management.color import no_style from django.db import connection from myapps.models import MyModel1, MyModel2 sequence_sql = connection.ops.sequence_reset_sql(no_style(), [MyModel1, MyModel2]) with connection.cursor() as cursor: for sql in sequence_sql: cursor.execute(sql) 

Ho provato questo codice con Python3.6 , Django 2.0 e PostgreSQL 10 .

Se vuoi reimpostare il PK su tutte le tue tabelle, come me, puoi usare il modo consigliato da PostgreSQL :

 SELECT 'SELECT SETVAL(' || quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) || ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1) ) FROM ' || quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';' FROM pg_class AS S, pg_depend AS D, pg_class AS T, pg_attribute AS C, pg_tables AS PGT WHERE S.relkind = 'S' AND S.oid = D.objid AND D.refobjid = T.oid AND D.refobjid = C.attrelid AND D.refobjsubid = C.attnum AND T.relname = PGT.tablename ORDER BY S.relname; 

Dopo aver eseguito questa query, sarà necessario eseguire i risultati della query. Di solito copio e incollo il blocco note. Quindi trovo e sostituisco "SELECT with SELECT and ;" con ; . Copia e incolla in pgAdmin III ed eseguo la query. Reimposta tutte le tabelle nel database. Altre istruzioni “professionali” sono fornite al link sopra.