web-dev-qa-db-ja.com

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の終わりに何かがあると思うが、私にはわからない。フィードバックは大歓迎です!

52
the_man_slim

これは私に起こります-Postgresで主キーフィールドを再同期する必要があることがわかりました。キーはSQLステートメントです。

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

これは、MySQLとSQLite(明示的なIDを持つオブジェクトを挿入する場合でも、次に利用可能な主キーを更新する)バックエンドと、Postgres、Oracleなどの他のバックエンドとの間の動作の既知の違いのようです。 。

同じ問題を説明するチケットがあります 。無効として閉じられたとしても、次の利用可能なキーを更新するためのDjango=管理コマンドがあるというヒントを提供します。

アプリケーションの次のすべてのIDを更新するSQLを表示するにはMyApp

python manage.py sqlsequencereset MyApp

ステートメントを実行するために、dbshel​​l管理コマンドの入力としてステートメントを提供できます。 bashの場合、次のように入力できます。

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

管理コマンドの利点は、基盤となるDBバックエンドが抽象化されるため、後で別のバックエンドに移行しても機能することです。

20
Ad N

同じ問題がありました。 「在庫」アプリに既存のテーブルがあり、Django adminに新しいレコードを追加したかったので、次のメッセージが表示されました。

重複したキー値が一意の制約「inventory_part_pkey」に違反しています詳細:キー(part_id)=(1)は既に存在します。

前述のように、以下のコードを実行して、id-sをリセットするSQLコマンドを生成します。

python manage.py sqlsequencereset inventory

私の場合 python manage.py sqlsequencereset MyApp | python manage.py dbshellは機能していませんでした

  • そこで、生成されたSQLステートメントをコピーしました。
  • その後、postgreSQLのpgAdminを開き、私のデータベースを開きました。
  • 6.アイコンをクリック(任意のSQLクエリを実行)
  • 生成されたステートメントをコピーしました。

私の場合、それは:

ベギン; SELECT setval(pg_get_serial_sequence( '"inventory_signup"'、 'id')、coalesce(max( "id")、1)、max( "id")IS NOT NULL)FROM "inventory_signup "; SELECT setval(pg_get_serial_sequence( '" inventory_supplier "'、 'id')、coalesce(max(" id ")、1)、max(" id ")IS NOT NULL)FROM "inventory_supplier"; COMMIT;

F5で実行しました。

これですべてのテーブルが修正され、最後に新しいレコードがid = 1に追加されずに最後に追加されました。

8
jturi

Zapphodsの答えに加えて:

私の場合、すべての移行を削除したため、インデックス作成は実際には正しくありませんでした。データベースは、移行の段階ではなかったため、開発時におそらく10〜15回削除されました。

finished_product_template_finishedproduct_pkeyでIntegrityErrorが発生していました

テーブルのインデックスを再作成し、runserverを再起動します。

私はpgadmin3を使用していましたが、どちらのインデックスが間違っていても重複キーエラーをスローして、constraintsに移動してインデックスを再作成しました。

enter image description here

そして、インデックスを再作成しました。

enter image description here

7
jmunsch

解決策は、サンプルのSQLコードを書いた「Hacking Life」によって報告された主キーフィールドを再同期する必要があることですが、「Ad N」によって示唆されるように、Djangoコマンドsqlsequenceresetコピーして貼り付けるか、別のコマンドで実行できる正確なSQLコードを取得します。

これらの回答に対するさらなる改善として、SQLコードをコピーして貼り付けないで、より安全に、pythonコード内からsqlsequenceresetによって生成されたSQLクエリを実行することをお勧めします。このように(デフォルトのデータベースを使用して):

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.6Django 2.およびPostgreSQL 1でこのコードをテストしました。

4

データベースを手動でコピーした場合は、 ここで説明する問題 が実行されている可能性があります。

3
zaphod

私のように、すべてのテーブルで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にコピーして貼り付け、クエリを実行します。データベース内のすべてのテーブルをリセットします。上記のリンクで、より「専門的な」指示が提供されています。

2
Bobort

間違った方法でsaveメソッドに余分な引数を渡していたため、このエラーが発生しました。

これに遭遇した人のために、UPDATEを強制してみてください:

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

force_insertforce_updateを同時に渡すことができないというエラーが発生した場合、おそらく私がしたように、いくつかのカスタム引数を間違った方法で渡しています。

2
jvannistelrooy

OPと同じエラーが表示されていました。

私はいくつかのDjango=モデルを作成し、モデルに基づいてPostgresテーブルを作成し、Django Admin。モデルの一部の列(ForeignKeysなどを変更)が、変更の移行を忘れていました。

移行コマンドを実行することで問題が解決しました。これは上記のSQLの答えを考えると理にかなっています。

実際に適用せずに、どの変更が適用されるかを確認するには:
python manage.py makemigrations --dry-run --verbosity 3

これらの変更に満足している場合は、次を実行します。
python manage.py makemigrations

次に実行します:
python manage.py migrate

0
allardbrain