Problemas com contenttypes ao carregar um fixture no Django

104

Estou tendo problemas para carregar acessórios Django em meu banco de dados MySQL por causa de conflitos de tipo de conteúdo. Primeiro tentei despejar os dados apenas do meu aplicativo, desta forma:

./manage.py dumpdata escola > fixture.json

mas não parava de ter problemas de chave estrangeira, pois meu app "escola" usa tabelas de outros aplicativos. Continuei adicionando aplicativos até chegar a este:

./manage.py dumpdata contenttypes auth escola > fixture.json

Agora, o problema é a seguinte violação de restrição quando tento carregar os dados como um dispositivo de teste:

IntegrityError: (1062, "Duplicate entry 'escola-t23aluno' for key 2")

Parece que o problema é que o Django está tentando recriar dinamicamente contenttypes com diferentes valores de chave primária que entram em conflito com os valores da chave primária do fixture. Parece ser o mesmo bug documentado aqui: http://code.djangoproject.com/ticket/7052

O problema é que a solução alternativa recomendada é descartar o aplicativo contenttypes, o que já estou fazendo !? O que da? Se fizer alguma diferença, tenho algumas permissões de modelo personalizado, conforme documentado aqui: http://docs.djangoproject.com/en/dev/ref/models/options/#permissions

gerdemb
fonte

Respostas:

148

manage.py dumpdata --naturalusará uma representação mais durável de chaves estrangeiras. No django, elas são chamadas de "chaves naturais". Por exemplo:

  • Permission.codename é usado em favor de Permission.id
  • User.username é usado em favor de User.id

Leia mais: seção de chaves naturais em "serializando objetos django"

Alguns outros argumentos úteis para dumpdata:

  • --indent=4 torná-lo legível por humanos.
  • -e sessions excluir dados da sessão
  • -e admin excluir histórico de ações administrativas no site de administração
  • -e contenttypes -e auth.Permissionexclua objetos que são recriados automaticamente do esquema todas as vezes durante syncdb. Use-o apenas junto com --naturalou você pode acabar com números de identificação mal alinhados.
Esqui
fonte
1
@skyjur Por que usar sempre -e contenttypes -e auth.permissioncom --natural? Eu apenas tentei sem a --naturalopção e funcionou. Além disso, a documentação aqui diz que se deve usar esta opção se DUMPING auth.permission e contenttypes.
wlnirvana
6
@winirvana porque depois de começar do zero e fazer o syncdb, o recém-criado ContentTypee Permissionnão tem garantia de obter o mesmo id que tinha antes. Seu dump de dados contém ids que podem fazer referência a diferentes objetos em outro banco de dados onde você irá carregar os dados. Pode funcionar para você por um destes motivos: 1) seus dados não tinham nenhuma referência a esses objetos 2) IDs originais de Permission / ContentTypes foram preservados 3) seu loaddata foi bem-sucedido, mas na verdade você tem dados corrompidos devido a objetos referindo-se a objetos errados e você ainda não sabe sobre isso
Ski
12
A bandeira --naturalfoi descontinuada em favor de --natural-foreign(e --natural-primary)
frnhr
16
O comando final pode ser:manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4 > project_dump.json
Paolo
4
--naturalagora foi completamente removido, não apenas obsoleto. Use --natural-foreignou em seu --natural-primarylugar.
Code-Apprentice
35

Sim, isso é realmente irritante. Por um tempo, resolvi fazer um "manage.py reset" no aplicativo contenttypes antes de carregar o fixture (para me livrar dos dados contenttypes gerados automaticamente que diferiam da versão despejada). Isso funcionou, mas eventualmente eu cansei dos aborrecimentos e abandonei os acessórios inteiramente em favor de dumps SQL diretos (é claro, então você perde a portabilidade do banco de dados).

atualizar - a melhor resposta é usar o --naturalsinalizador para dumpdata, conforme observado em uma resposta abaixo. Essa bandeira ainda não existia quando escrevi esta resposta.

Carl Meyer
fonte
3
Eu estava correndo para isso também, redefinir o aplicativo contenttypes funcionou para mim também. Obrigado pela dica!
Beau de
Como você os redefiniu? Na aula de caso de teste? Dê-me um exemplo, por favor
Oleg Tarasenko
4
Eu não uso fixtures para unittests, geralmente crio dados de teste usando o ORM em um método setup () porque é mais fácil manter em sincronia com os testes. Então, eu nunca tive que fazer isso em uma classe TestCase, embora eu tenha certeza que se você vasculhar o código da classe TestCase do Django, poderá descobrir como fazer uma reinicialização acontecer após o syncdb e antes do carregamento do fixture em uma subclasse. Para mim, era apenas "./manage.py reset contenttypes" em um script bash anterior a "./manage.py loaddata my_fixture".
Carl Meyer,
32

Tente pular contenttypes ao criar fixture:

./manage.py dumpdata --exclude contenttypes > fixture.json

Funcionou para mim em uma situação semelhante para testes de unidade, sua visão sobre os tipos de conteúdo realmente ajudou!

Evgeny
fonte
31

As respostas aqui são todas antigas ... A partir de 2017, a melhor resposta é:

manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4
Olá Mundo
fonte
11

Eu não estava usando o MySQL, mas importando alguns dados de um servidor ativo para o sqlite. Limpar os contenttypesdados do aplicativo antes de executar loaddatao truque:

from django.contrib.contenttypes.models import ContentType
ContentType.objects.all().delete()
quit()

E depois

python manage.py loaddata data.json
MadeOfAir
fonte
django.core.exceptions.ImproperlyConfigured: Configuração solicitada INSTALLED_APPS, mas as configurações não foram configuradas. Você deve definir a variável de ambiente DJANGO_SETTINGS_MODULE ou chamar settings.configure () antes de acessar as configurações.
Barney
Provavelmente funcionaria melhor com um comando de gerenciamento personalizado.
Barney
10

Resolvi esse problema em meus casos de teste redefinindo o aplicativo contenttypes do teste de unidade antes de carregar meu arquivo de despejo. Carl sugeriu isso já usando o manage.pycomando e eu faço a mesma coisa apenas usando o call_commandmétodo:

>>> from django.core import management
>>> management.call_command("flush", verbosity=0, interactive=False)
>>> management.call_command("reset", "contenttypes", verbosity=0, interactive=False)
>>> management.call_command("loaddata", "full_test_data.json", verbosity=0)

Meu full_test_data.jsonfixture contém o dump do app contenttypes que corresponde ao resto dos dados de teste. Ao redefinir o aplicativo antes de carregar, evita a duplicação da chave IntegrityError.

Jesse L
fonte
7
python manage.py dumpdata --natural-primary --exclude=contenttypes --exclude=auth.Permission --exclude=admin.logentry --exclude=sessions.session --indent 4 > initial_data.json

Isso funciona para mim. Aqui estou excluindo tudo dos modelos reais.

  • Se você vir qualquer outro modelo diferente dos modelos que você criou, pode excluí-los com segurança. Uma desvantagem dessa abordagem é que você perde tanto nos dados de log quanto nos dados de autenticação.
Ojas Kale
fonte
6

Você precisa usar chaves naturais para representar qualquer chave estrangeira e relacionamentos muitos para muitos. Além disso, pode ser uma boa ideia excluir a sessiontabela no sessionsaplicativo e a logentrytabela no adminaplicativo.

Django 1.7+

python manage.py dumpdata --natural-foreign --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json

Django <1.7

python manage.py dumpdata --natural --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json

De acordo com a documentação do Django , --naturalestá obsoleto na versão 1.7, portanto, a opção --natural-foreigndeve ser usada em seu lugar.

Você também pode omitir a chave primária nos dados serializados deste objeto, pois ela pode ser calculada durante a desserialização, passando o --natural-primarysinalizador.

python manage.py dumpdata --natural-foreign --natural-primary --exclude contenttypes --exclude auth.permission --exclude admin.logentry --exclude sessions.session --indent 4 > fixture.json
lmiguelvargasf
fonte
2
./manage.py dumpdata app.Model --natural-foreign

vai mudar

  "content_type": 123

para

  "content_type": [
    "app_label",
    "model"
  ],

E a fixação funciona por TestCaseagora

Daniil Mashkin
fonte
2

Django 2.2.5

python manage.py dumpdata --exclude=contenttypes > datadump.json

isso me ajudou

Igor Z
fonte
Isso levantará problemas quando loaddata, talvez incompatibilidade com contenttype no novo banco de dados
yang zhou,
1

Vou dar outra resposta possível que acabei de descobrir. Talvez ajude o OP, talvez ajude outra pessoa.

Eu tenho uma tabela de relacionamento muitos para muitos. Ele possui uma chave primária e as duas chaves estrangeiras para as outras tabelas. Eu descobri que se eu tiver uma entrada no aparelho cujas duas chaves estrangeiras são iguais a outra entrada já na tabela com um pk diferente , ele irá falhar. As tabelas de relacionamento M2M têm um "conjunto único" para as duas chaves estrangeiras.

Então, se é um relacionamento M2M que está rompendo, olhe as chaves estrangeiras que está adicionando, olhe seu banco de dados para ver se aquele par de FKs já está listado em um PK diferente.

orblivion
fonte
1

É muito, muito chato .. Eu sou mordido por isso toda vez.

Tentei despejar dados com --exclude contenttypes e --natural, sempre tive problemas ..

O que funciona melhor para mim é simplesmente fazer um truncate table django_content_type;após o syncdb e ENTÃO carregar os dados.

É claro que, para o carregamento automático de initial_data.json, você é fallball.

h3.
fonte
Para mim, truncar a tabela antes de loaddata só causa erros diferentes. Sem sorte com esta técnica.
shacker de
1

Eu havia encontrado um erro semelhante algumas vezes atrás. Acontece que eu estava tentando carregar as luminárias antes de criar as tabelas necessárias. Então eu fiz:

$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py loaddata fixtures/initial_data.json

e funcionou perfeitamente

James Wanderi
fonte
0

No meu caso, eu tinha despejado os dados de auth( ./manage.py dumpddata auth > fixtures/auth.json) para usar o fixture para fins de teste.

O desenvolvimento continuou e eu removi a maioria dos modelos que tinha definido models.pye foi aí que comecei a ver esse problema chato.

Minha solução foi regenerar o dispositivo auth.json novamente. Este tinha removido muitas entradas auth.permissionrelacionadas aos modelos antigos que eu tinha.

Pablo Castellano
fonte
0

Eu tentei todos os métodos de cima, nada funcionou para mim. Tenho que excluir o modelo de autenticação completo e funciona bem.

python manage.py dumpdata --natural-primary --exclude=contenttypes --exclude=auth --exclude=admin.logentry --exclude=sessions.session --indent 4 > live.json
Chandra Shekhar Pandey
fonte