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 и переиндексация.

enter image description here

и потом переиндексирован.

enter image description here


Если вы вручную скопировали базы данных, вы можете запустить в проблема описана здесь.


у меня была та же проблема. У меня была существующая таблица в моем приложении "инвентарь", и я хотел добавить новые записи в 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 и запускаю запрос. Он сбрасывает все таблицы в базе данных. Более "профессиональные" инструкции предоставляются по ссылке выше.