Estou usando o Django e de vez em quando recebo este erro:
IntegrityError: valor de chave duplicado viola restrição exclusiva "myapp_mymodel_pkey"
DETALHE: A chave (id)=(1) já existe.
Meu banco de dados Postgres de fato tem um objeto myapp_mymodel com a chave primária de 1.
Por que o Postgres tentaria usar essa chave primária novamente? Ou é mais provável que meu aplicativo (ou ORM do Django) esteja causando isso?
Este problema ocorreu mais 3 vezes seguidas agora. O que descobri é que, quando ocorre , acontece uma ou mais vezes seguidas para uma determinada tabela, e não novamente. Parece acontecer para todas as mesas antes de parar completamente por dias, acontecendo por pelo menos um minuto ou mais por mesa quando ocorre, e acontecendo apenas intermitentemente (nem todas as mesas imediatamente).
O fato de esse erro ser tão intermitente (aconteceu apenas 3 ou mais vezes em 2 semanas - nenhuma outra carga no banco de dados, apenas eu testando meu aplicativo) é o que me deixa tão cauteloso com um problema de baixo nível.
O PostgreSQL não tentará inserir valores duplicados por conta própria, é você (seu aplicativo, ORM incluído) quem o faz.
Pode ser tanto uma sequência alimentando os valores para o PK configurado para a posição errada e a tabela já contendo o valor igual ao seu
nextval()
- ou simplesmente que sua aplicação faz a coisa errada. O primeiro é fácil de corrigir:O segundo significa depuração.
O Django (ou qualquer outro framework popular) não redefine as sequências por conta própria - caso contrário, teríamos perguntas semelhantes a cada dois dias.
Você provavelmente está tentando inserir uma linha em uma tabela para a qual o valor da sequência da coluna serial não é atualizado.
Considere a seguinte coluna em sua tabela que é a chave primária definida pelo Django ORM para postgres
Cujo valor padrão é definido como
A sequência só é avaliada quando o campo id está em branco. Mas isso é um problema se já houver entradas na tabela.
A pergunta é por que essas entradas anteriores não acionaram a atualização de sequência? Isso ocorre porque o valor de id foi fornecido explicitamente para todas as entradas anteriores.
No meu caso, essas entradas iniciais foram carregadas de fixtures por meio de migrações.
Esse problema também pode ser complicado por meio de entradas personalizadas com valor PK aleatório.
Diga por exemplo. Há 10 entradas em sua tabela. Você faz uma entrada explícita com PK=15. As próximas quatro inserções através do código funcionariam perfeitamente bem, mas a quinta geraria uma exceção.
Acabei aqui com o mesmo erro, que acontecia raramente e era difícil de rastrear, porque eu estava procurando por ele não onde deveria.
A falha foi a repetição do JS que estava fazendo o POST para o servidor duas vezes! Então, às vezes vale a pena dar uma olhada não apenas em suas visualizações e formulários do django (ou qualquer outro framework da web), mas também o que acontece na parte frontal.
Você também pode alterar a sequência sem nenhum script SQL pela GUI pgAdmin conforme abaixo:
selecione seu banco de dados -> esquemas -> público -> sequências -> clique com o botão direito -> propriedades -> definição -> valor atual.
Sim, coisa estranha. No meu caso, algo aparentemente deu errado durante o carregamento de dados nas migrações. Adicionei a migração vazia e escrevi as linhas para adicionar alguns dados iniciais, 6 registros no meu caso.
Então, no painel de administração, tentei adicionar um novo item e obtive:
Primeira tentativa:
Tentativas posteriores:
E finalmente a 7ª e as vezes são todas bem sucedidas
Então, estou dizendo que pode haver algo relacionado a bulk_create, pois carreguei 6 itens lá. Talvez seja algo semelhante em seu projeto Django causando isso.
Django 1.9 PostgreSQL 9.3.14
Isso aconteceu comigo porque inseri registros usando valores literais e numéricos (em vez de DEFAULT ou indefinido) como argumentos para a coluna incrementada automaticamente. Isso evita a chamada de incremento do objeto de sequência subjacente da coluna, tornando o valor da sequência fora de sincronia com os valores da coluna na tabela.
Você também pode fazer isso: