El valor de la clave duplicada de IntegrityError viola la restricción única-django/postgres
postgresql duplicates (8)
Además de zapphods respuesta:
En mi caso, la indexación era realmente incorrecta, ya que había eliminado todas las migraciones, y la base de datos probablemente 10-15 veces cuando se desarrollaba, ya que no estaba en la etapa de migración de nada.
Estaba obteniendo un IntegrityError en finished_product_template_finishedproduct_pkey
Reindexe la tabla y reinicie el servidor de ejecución:
Estaba usando pgadmin3 y para cualquier índice que fuera incorrecto y arrojando errores clave duplicados navegué a las constraints
y reindexé.
Y luego reindexado.
Estoy dando seguimiento a una pregunta que hice antes, en la que busqué una conversión de una consulta misteriosa / mal escrita de mysql a postgresql. Creo que tuve éxito con eso. De todos modos, estoy usando datos que se movieron manualmente desde una base de datos mysql a una base de datos postgres. Estoy usando una consulta que se ve así:
"""
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)
)
Tengo razones para creer que esto funciona bien. Sin embargo, esto ha llevado a un nuevo problema. Al intentar enviar, recibo un error de django que dice:
IntegrityError at (some url):
duplicate key value violates unique constraint "krypdos_value_pkey"
He visto varias de las respuestas publicadas aquí y no he encontrado la solución a mi problema (aunque las preguntas relacionadas han sido una lectura interesante). Veo esto en mis registros, lo cual es interesante porque nunca llamo explícitamente a insertar- django debe manejarlo:
STATEMENT: INSERT INTO "krypdos_value" ("code_round_id", "variable_id", "option_id", "confidence", "freetext")
VALUES (1105935, 11, 55, NULL, E'''')
RETURNING "krypdos_value"."id"
Sin embargo, al tratar de ejecutar eso se obtiene el error duplicado de la clave. El error real se arroja en el código a continuación.
# 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(
He revisado las secuencias y tal parece que están en orden. En este punto, no estoy seguro de qué hacer, supongo que es algo al final de Django, pero no estoy seguro. ¡Cualquier comentario sería muy apreciado!
Encontré este error porque estaba pasando argumentos adicionales al método de guardar de la manera incorrecta.
Para cualquiera que se encuentre con esto, intente forzar la ACTUALIZACIÓN con:
instance_name.save(..., force_update=True)
Si obtiene un error que no puede pasar force_insert
y force_update
al mismo tiempo, probablemente esté pasando algunos argumentos personalizados de la manera incorrecta, como yo lo hice.
Esto me pasó a mí, resulta que necesitas volver a sincronizar tus campos de clave principal en Postgres. La clave es la declaración de SQL:
SELECT setval(''tablename_id_seq'', (SELECT MAX(id) FROM tablename)+1)
La solución es que necesita resincronizar los campos de claves principales según lo informado por "Hacking Life", que escribió un código SQL de ejemplo pero, como sugiere "Ad N", es mejor ejecutar el comando sqlsequencereset
Django para obtener el código SQL exacto que usted puede copiar y pasar o ejecutar con otro comando.
Como una mejora adicional de estas respuestas, le sugiero a usted y a otros lectores que no copien y peguen el código SQL, sino que ejecuten la consulta SQL generada por sqlsequencereset
desde su código python de esta manera ( utilizando la base de datos predeterminada). )
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)
Probé este código con Python3.6 , Django 2.0 y PostgreSQL 10 .
Parece ser una diferencia de comportamiento conocida entre MySQL y SQLite (actualizan la próxima clave primaria disponible incluso cuando se inserta un objeto con un id. Explícito) backends, y otros backends como Postgres, Oracle, ... (no lo hacen) .
Hay un boleto que describe el mismo problema . Aunque se cerró como no válido, proporciona una pista de que hay un comando de administración de Django para actualizar la siguiente clave disponible.
Para mostrar el SQL actualizando todos los siguientes identificadores para la aplicación MyApp :
python manage.py sqlsequencereset MyApp
Para ejecutar la instrucción, puede proporcionarla como entrada para el comando de administración de dbshell . Para bash, podrías escribir:
python manage.py sqlsequencereset MyApp | python manage.py dbshell
La ventaja de los comandos de administración es que abstrae el back-end subyacente de DB, por lo que funcionará incluso si más adelante migra a un back-end diferente.
Si desea restablecer el PK en todas sus tablas, como yo, puede utilizar la forma recomendada de 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;
Después de ejecutar esta consulta, deberá ejecutar los resultados de la consulta. Normalmente copio y pego en el Bloc de notas. Luego encuentro y reemplazo "SELECT
with SELECT
and ;"
con ;
. Copio y pego en pgAdmin III y ejecuto la consulta. Restablece todas las tablas en la base de datos. Más instrucciones "profesionales" se proporcionan en el enlace de arriba.
Si ha copiado manualmente las bases de datos, es posible que se encuentre con el problema que se describe aquí .
Tuve el mismo problema. Tenía una tabla existente en mi aplicación de "inventario" y quería agregar nuevos registros en django admin y obtuve estos mensajes:
El valor duplicado de la clave viola la restricción única "inventory_part_pkey" DETAIL: La clave (part_id) = (1) ya existe.
Como se mencionó anteriormente, ejecute el siguiente código para generar un comando SQL para restablecer los id-s:
python manage.py sqlsequencereset inventory
En mi caso, python manage.py sqlsequencereset MyApp | python manage.py dbshell
python manage.py sqlsequencereset MyApp | python manage.py dbshell
no funcionaba
- Así que copié la declaración SQL generada.
- Luego abrí pgAdmin para postgreSQL y abrí mi db.
- Haga clic en el ícono 6. (Ejecutar consultas SQL arbitrarias)
- Copió la declaración de lo que se generó.
En mi caso fue:
EMPEZAR; SELECT setval (pg_get_serial_sequence (''"inventory_signup"'', ''id''), coalesce (max ("id"), 1), max ("id") NO ES nulo) FROM "inventory_signup"; SELECT setval (pg_get_serial_sequence (''"inventory_supplier"'', ''id''), coalesce (max ("id"), 1), max ("id") NO ES nulo) FROM "inventory_supplier"; COMETER;
Se ejecutó con F5.
Esto arregló todas mis tablas y finalmente agregó nuevos registros al final, sin intentar agregarlo a id = 1.