IntegrityError повторяющееся значение ключа нарушает уникальное ограничение-django/postgres
Я следую в отношении вопрос, который я задавал ранее в котором я пытался найти преобразование из тупого / плохо написанного запроса mysql в postgresql. Думаю, мне это удалось. В любом случае, я использую данные, которые были вручную перемещены из базы данных mysql в базу данных postgres. Я использую запрос, который выглядит так:
"""
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)
)
у меня есть основания полагать, что это хорошо работает. Однако это привело к новому вопросу. Когда я пытаюсь подчиниться, я получаю ошибка от django, которая гласит:
IntegrityError at (some url):
duplicate key value violates unique constraint "krypdos_value_pkey"
Я просмотрел несколько ответов, размещенных здесь, и я не совсем нашел решение своей проблемы (хотя связанные с этим вопросы сделали для некоторого интересного чтения). Я вижу это в своих журналах, что интересно, потому что я никогда явно не вызываю insert-django должен обрабатывать его:
STATEMENT: INSERT INTO "krypdos_value" ("code_round_id", "variable_id", "option_id", "confidence", "freetext")
VALUES (1105935, 11, 55, NULL, E'')
RETURNING "krypdos_value"."id"
однако попытка запустить это приводит к ошибке дубликата ключа. Фактическая ошибка в коде под.
# 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(
Я проверил последовательности и тому подобное, и они, похоже, в порядке. На данный момент я не уверен, что делать - я предполагаю, что это что-то на конце Джанго, но я не уверен. Любая обратная связь будет высоко ценится!
8 ответов
это случилось со мной-оказывается, вам нужно повторно синхронизировать поля первичного ключа в Postgres. Ключом является оператор SQL:
SELECT setval('tablename_id_seq', (SELECT MAX(id) FROM tablename)+1)
похоже, что это известная разница в поведении между MySQL и SQLite (они обновляют следующий доступный первичный ключ даже при вставке объекта с явным идентификатором) бэкэнды и другие бэкэнды, такие как Postgres, Oracle, ... (они не).
есть билет, описывающий тот же вопрос. Несмотря на то, что он был закрыт как недопустимый, он дает намек на то, что есть команда управления Django для обновления следующего доступного ключа.
для отображения SQL обновляет все следующие идентификаторы для приложения MyApp:
python manage.py sqlsequencereset MyApp
чтобы выполнить оператор, вы можете предоставить его в качестве входных данных для dbshell команды управления. Для bash вы можете ввести:
python manage.py sqlsequencereset MyApp | python manage.py dbshell
преимущество команд управления заключается в том, что абстрагирует базовый сервер БД, поэтому он будет работать, даже если позже будет перенесен на другой сервер.
в дополнение к zapphods ответ:
в моем случае индексирование было действительно неправильным, так как я удалил все миграции, и база данных, вероятно, 10-15 раз при разработке, поскольку я не был в стадии миграции чего-либо.
Я получал IntegrityError на finished_product_template_finishedproduct_pkey
Переиндексируйте таблицу и перезапустите runserver:
я использовал pgadmin3 и для любого индекса был неправильным и бросал повторяющиеся ключевые ошибки, которые я перешел к constraints
и переиндексация.
и потом переиндексирован.
Если вы вручную скопировали базы данных, вы можете запустить в проблема описана здесь.
у меня была та же проблема. У меня была существующая таблица в моем приложении "инвентарь", и я хотел добавить новые записи в Django admin, и я получил эти сообщения:
повторяющееся значение ключа нарушает уникальное ограничение " inventory_part_pkey" Деталь: ключ (part_id)=(1) уже существует.
Как упоминалось ранее, запустите код ниже, чтобы получить команду SQL для сброса id-s:
python manage.py sqlsequencereset inventory
в моем случае python manage.py sqlsequencereset MyApp | python manage.py dbshell
не было работа
- поэтому я скопировал сгенерированный оператор SQL.
- затем открыл pgAdmin для postgreSQL и открыл мою БД.
- нажал на 6. значок (выполнение произвольных SQL-запросов)
- скопировал инструкцию, которая была сгенерирована.
в моем случае это было:
начать; Выберите setval (pg_get_serial_sequence ('"inventory_signup"', 'id'), coalesce (max ("id"), 1), max ("id") не равно null) из "inventory_signup"; Выберите setval (pg_get_serial_sequence ('"inventory_supplier"',' id'), coalesce (max ("id"), 1), max ("id") не равно null) из " inventory_supplier"; Совершить;
выполнил его с помощью F5.
это исправило все мои таблицы и, наконец, добавив новые записи в конец, не пытаясь добавить его в id = 1 больше.
решение заключается в том, что вам нужно повторно синхронизировать поля первичного ключа, Как сообщает "Hacking Life", который написал пример кода SQL, но, как предложено "Ad N", лучше запустить команду Django sqlsequencereset
чтобы получить точный код SQL, который вы можете скопировать и пройти или запустить с другой командой.
в качестве дальнейшего улучшения этих ответов я бы предложил вам и другому читателю не копировать и вставлять код SQL, но, более безопасно, выполнять SQL-запрос, сгенерированный sqlsequencereset
от в вашем коде python таким образом (использование базы данных по умолчанию):
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)
я протестировал этот код с помощью Питон3.6, Джанго 2.0 и PostgreSQL 10.
я столкнулся с этой ошибкой, потому что я неправильно передавал дополнительные аргументы методу save.
для всех, кто сталкивается с этим, попробуйте принудительное обновление с:
instance_name.save(..., force_update=True)
Если вы получаете ошибку, которую вы не можете передать force_insert
и force_update
в то же время вы, вероятно, передаете некоторые пользовательские аргументы неправильно, как и я.
если вы хотите сбросить ПК на всех ваших таблицах, как я, вы можете использовать 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;
после выполнения этого запроса вам нужно будет выполнить результаты запроса. Обычно я копирую и вставляю в блокнот. Затем я нахожу и заменяю "SELECT
С SELECT
и ;"
С ;
. Я копирую и вставляю в pgAdmin III и запускаю запрос. Он сбрасывает все таблицы в базе данных. Более "профессиональные" инструкции предоставляются по ссылке выше.