Подтвердить что ты не робот

Целочисленное ключевое значение 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(

Я проверил последовательности и такие, и они, похоже, в порядке. На данный момент я не уверен, что делать - я предполагаю, что это что-то на django, но я не уверен. Любая обратная связь будет высоко оценена!

4b9b3361

Ответ 1

Это случилось со мной - оказывается, вам нужно повторно синхронизировать поля первичного ключа в Postgres. Ключ - это оператор SQL:

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

Ответ 2

Похоже, что это известное различие в поведении между MySQL и SQLite (они обновляют следующий доступный первичный ключ, даже когда вставляют объект с явным id), и другие бэкэнды, такие как Postgres, Oracle,... (они не).

Существует билет, описывающий ту же проблему. Несмотря на то, что он был закрыт как недопустимый, он дает подсказку о том, что есть команда управления Django для обновления следующего доступного ключа.

Чтобы отобразить SQL-обновление всех следующих идентификаторов для приложения MyApp:

python manage.py sqlsequencereset MyApp

Чтобы выполнить оператор, вы можете указать его как вход для команды управления dbshell. Для bash вы можете ввести:

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

Преимущество команд управления заключается в том, что он абстрагирует базовый сервер базы данных, поэтому он будет работать, даже если позже будет перенесен на другой бэкэнд.

Ответ 3

В дополнение к ответам zapphods:

В моем случае индексирование действительно было неправильным, так как я удалил все миграции, а база данных, вероятно, 10-15 раз при разработке, поскольку я не был в стадии миграции чего-либо.

Я получал IntegrityError на finished_product_template_finishedproduct_pkey

Переинсталлировать таблицу и перезапустить серверы запуска:

Я использовал pgadmin3 и для того, что индекс был неправильным и выбрасывал повторяющиеся ключевые ошибки, я перешел к constraints и повторно проиндексирован.

enter image description here

И затем снова проиндексируется.

enter image description here

Ответ 4

У меня была такая же проблема. У меня была существующая таблица в моем приложении "inventory", и я хотел добавить новые записи в admin django, и я получил эти сообщения:

Повторяющееся значение ключа нарушает уникальное ограничение "inventory_part_pkey" ДЕТАЛИ: Key (part_id) = (1) уже существует.

Как уже упоминалось выше, выполните следующий код, чтобы получить команду SQL для reset id-s:

python manage.py sqlsequencereset inventory

В моем случае python manage.py sqlsequencereset MyApp | python manage.py dbshell не работает

  • Итак, я скопировал сгенерированный оператор SQL.
  • Затем открыл pgAdmin для postgreSQL и открыл мой db.
  • Нажмите на значок 6. (Выполняйте произвольные SQL-запросы)
  • Скопировано утверждение о том, что было создано.

В моем случае это было:

НАЧАТЬ; SELECT setval (pg_get_serial_sequence (' "inventory_signup",' id '), coalesce (max ( "id" ), 1), max ( "id" ) НЕ НЕВОЗМОЖНО) FROM "inventory_signup"; SELECT setval (pg_get_serial_sequence (' "inventory_supplier" ', 'id'), coalesce (max ( "id" ), 1), max ( "id" ) НЕ НЕВОЗМОЖНО) FROM "inventory_supplier"; COMMIT;

Выполнено с помощью F5.

Это фиксировало все мои таблицы и, наконец, добавило новые записи в конец, не пытаясь добавить его к id = 1.

Ответ 5

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

Ответ 6

Решение состоит в том, что вам необходимо sqlsequencereset поля первичного ключа, как сообщил "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)

Я тестировал этот код с Python3.6, Django 2.0 и PostgreSQL 10.

Ответ 7

Я столкнулся с этой ошибкой, потому что я передал дополнительные аргументы методу сохранения не так.

Для всех, кто сталкивается с этим, попробуйте форсировать UPDATE с помощью:

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

Если вы получите сообщение об ошибке, которое вы не можете передать force_insert и force_update одновременно, вы, вероятно, передаете некоторые пользовательские аргументы неправильно, как я.

Ответ 8

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

Ответ 9

Я получал ту же ошибку, что и ОП.

Я создал несколько моделей Django, создал таблицу Postgres на основе этих моделей и добавил несколько строк в таблицу Postgres через Django Admin. Затем я возился с некоторыми из столбцов в моделях (переходя на ForeignKeys и т.д.), Но забыл перенести изменения.

Выполнение команд миграции решило мою проблему, которая имеет смысл, учитывая приведенные выше ответы на SQL.

Чтобы увидеть, какие изменения будут применены, фактически не применяя их:
python manage.py makemigrations --dry-run --verbosity 3

Если вы довольны этими изменениями, запустите:
python manage.py makemigrations

Затем запустите:
python manage.py migrate