IntegrityError duplicate key value narusza unikalne ograniczenie-django / postgres

Podążam za pytaniem , które zadałem wcześniej, w którym Szukałem konwersji z głupiego/źle napisanego zapytania mysql do postgresql. Wierzę, że mi się to udało. Tak czy inaczej, używam danych, które zostały ręcznie przeniesione z bazy danych mysql do bazy danych postgres. Używam zapytania, które wygląda tak:

  """
  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)
  )
Mam powody sądzić, że to działa dobrze. Doprowadziło to jednak do nowej kwestii. Podczas próby przesłania otrzymuję błąd z django stwierdza się:
IntegrityError at (some url): 
duplicate key value violates unique constraint "krypdos_value_pkey"

Przejrzałem kilka odpowiedzi zamieszczonych tutaj i nie do końca znalazłem rozwiązanie mojego problemu (chociaż powiązane pytania sprawiły, że można je ciekawie przeczytać). Widzę to w moich logach, co jest ciekawe, ponieważ nigdy jawnie nie wywołuję insert-django musi to obsłużyć:

   STATEMENT:  INSERT INTO "krypdos_value" ("code_round_id", "variable_id", "option_id", "confidence", "freetext")
   VALUES (1105935, 11, 55, NULL, E'') 
   RETURNING "krypdos_value"."id"

Jednak próba uruchomienia powoduje błąd duplikatu klucza. Rzeczywisty błąd jest wyrzucany w kodzie poniżej.

 # 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(

Sprawdziłem sekwencje i takie i wydają się być w porządku. W tym momencie Nie jestem pewien, co robić - zakładam, że to coś na końcu django, ale nie jestem pewien. Wszelkie opinie będą mile widziane!

Author: Community, 2012-06-18

8 answers

To mi się przydarzyło-okazuje się, że musisz ponownie zsynchronizować swoje główne pola kluczowe w Postgres. Kluczem jest polecenie SQL:

SELECT setval('tablename_id_seq', (SELECT MAX(id) FROM tablename)+1)
 106
Author: Hacking Life,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-06 05:03:25

Wydaje się, że jest to znana różnica między backendami MySQL i SQLite (aktualizują następny dostępny klucz podstawowy nawet podczas wstawiania obiektu o jawnym id), a innymi backendami, takimi jak Postgres, Oracle,... (nie mają).

Istnieje bilet opisujący ten sam problem . Nawet jeśli został zamknięty jako nieprawidłowy, dostarcza podpowiedzi, że istnieje polecenie zarządzania Django, aby zaktualizować następny dostępny klucz.

Aby wyświetlić aktualizację SQL wszystkie następne ID dla aplikacji MyApp :

python manage.py sqlsequencereset MyApp

Aby polecenie zostało wykonane, możesz podać je jako dane wejściowe dla polecenia zarządzającego dbshell . Dla Basha można wpisać:

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

Zaletą poleceń zarządzania jest to, że pobiera bazowy backend DB, więc będzie działał nawet w przypadku późniejszej migracji do innego backendu.

 12
Author: Ad N,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-17 14:24:40

Oprócz zapphods odpowiedź:

W moim przypadku indeksowanie było rzeczywiście błędne, ponieważ usunąłem wszystkie Migracje, a baza danych prawdopodobnie 10-15 razy podczas tworzenia, ponieważ nie byłem na etapie migracji czegokolwiek.

Dostałem IntegrityError na finished_product_template_finishedproduct_pkey

Reindex tabeli i restart runserver:

Używałem pgadmin3 i dla tego, który indeks był niepoprawny i rzucał duplikaty błędów klawiszy nawigowałem do constraints i renifer.

Tutaj wpisz opis obrazka

/ Align = "left" /

Tutaj wpisz opis obrazka

 7
Author: jmunsch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-21 21:42:14

Jeśli ręcznie skopiowałeś bazy danych, możesz napotkać problem opisany tutaj .

 3
Author: zaphod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-18 20:00:04

Miałem ten sam problem. Miałem istniejącą tabelę w mojej aplikacji "inventory" i chciałem dodać nowe rekordy w django admin i dostałem te wiadomości:

Zduplikowana wartość klucza narusza unikalne ograniczenie " inventory_part_pkey" DETAIL: Key (part_id) = (1) już istnieje.

Jak wspomniano wcześniej Uruchom poniższy kod, aby wygenerować polecenie SQL, aby zresetować id-s:

python manage.py sqlsequencereset inventory

W moim przypadku python manage.py sqlsequencereset MyApp | python manage.py dbshell nie działa

  • więc skopiowałem wygenerowany SQL oświadczenie.
  • następnie otworzyłem pgAdmin dla postgreSQL i otworzyłem mój db.
  • Kliknij na 6. icon (wykonaj dowolne zapytania SQL)
  • skopiował to, co zostało wygenerowane.

W moim przypadku było:

BEGIN; Wybierz setval(pg_get_serial_sequence('"inventory_signup"','id'), coalesce(max("id"), 1), max("id") nie jest null) z "inventory_signup"; SELECT setval(pg_get_serial_sequence('"inventory_supplier"','id'), coalesce (max ("id"), 1), max ("id") nie jest null) z "inventory_supplier"; COMMIT;

Wykonałem z F5.

To poprawiło wszystkie moje tabele i ostatecznie dodało nowe rekordy do końca, nie próbując już dodawać go do id = 1.

 3
Author: Jozsef Turi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-22 15:45:50

Rozwiązaniem jest to, że musisz ponownie zsynchronizować swoje podstawowe pola klucza, jak donosi "Hacking Life", który napisał przykładowy kod SQL, ale, jak sugeruje "Ad N", Lepiej jest uruchomić polecenie Django sqlsequencereset, Aby uzyskać dokładny kod SQL, który możesz skopiować i przekazać lub uruchomić za pomocą innego polecenia.

Jako dalsze ulepszenie tych odpowiedzi sugerowałbym Tobie i innym czytelnikom, aby nie kopiować i wklejać kodu SQL, ale bezpieczniej wykonać zapytanie SQL wygenerowane przez sqlsequencereset z wewnątrz twojego kod Pythona w ten sposób (używając domyślnej bazy danych):

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)

Testowałem ten kod z Python3.6, Django 2.0 i PostgreSQL 10.

 3
Author: Paolo Melchiorre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-12 11:34:21

Napotkałem ten błąd, ponieważ przekazywałem dodatkowe argumenty do metody save w niewłaściwy sposób.

Dla każdego, kto napotka to, spróbuj wymusić UPDATE z:

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

Jeśli pojawi się błąd, którego nie możesz przekazać force_insert i force_update w tym samym czasie, prawdopodobnie przekazujesz niektóre niestandardowe argumenty w niewłaściwy sposób, tak jak ja.

 2
Author: jvannistelrooy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-02 13:01:14

Jeśli chcesz zresetować PK na wszystkich swoich stołach, tak jak ja, możesz użyć PostgreSQL recommended way :

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;

Po uruchomieniu tego zapytania, będziesz musiał wykonać wyniki zapytania. Zazwyczaj kopiuję i wklejam do Notatnika. Następnie znajduję i zamieniam "SELECT na SELECT i ;" na ;. Kopiuję i wklejam do pgAdmin III i uruchamiam zapytanie. Resetuje wszystkie tabele w bazie danych. Więcej "profesjonalnych" instrukcji znajduje się pod linkiem powyżej.

 1
Author: Bobort,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-14 17:56:30