Problems with contenttypes when loading a fixture in Django

I am having trouble loading Django fixtures into my MySQL database because of contenttypes conflicts. First I tried dumping the data from only my app like this:

./manage.py dumpdata escola > fixture.json

but I kept getting missing foreign key problems, because my app "escola" uses tables from other applications. I kept adding additional apps until I got to this:

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

Now the problem is the following constraint violation when I try to load the data as a test fixture:

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

It seems the problem is that Django is trying to dynamically recreate contenttypes with different primary key values that conflict with the primary key values from the fixture. This appears to be the same as bug documented here: http://code.djangoproject.com/ticket/7052

The problem is that the recommended workaround is to dump the contenttypes app which I'm already doing!? What gives? If it makes any difference I do have some custom model permissions as documented here: http://docs.djangoproject.com/en/dev/ref/models/options/#permissions

50301 次浏览

是的,这真的很烦人。有一段时间,我通过在加载 fixture 之前在内容类型应用程序上执行“ manage.py 重置”来解决这个问题(以去除自动生成的与转储版本不同的内容类型数据)。这种方法很有效,但是最终我厌倦了这种麻烦,完全放弃了装置,转而支持直接的 SQL 转储(当然,这样就失去了 DB 的可移植性)。

Update -最好的答案是对 dumpdata使用 --natural标志,如下面的答案所示。当我写这个答案的时候,那面旗子还不存在。

在创建 fixture 时尝试跳过内容类型:

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

它在单元测试的类似情况下对我很有用,您对内容类型的洞察力真的很有帮助!

在加载转储文件之前,通过从单元测试中重置内容类型应用程序,我已经在测试用例中解决了这个问题。卡尔已经使用 manage.py命令提出了这个建议,而我只使用 call_command方法做了同样的事情:

>>> 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)

我的 full_test_data.json fixture 包含与其余测试数据对应的内容类型 app dump。通过在加载前重置应用程序,它可以防止重复键 IntegrityError

manage.py dumpdata --natural将使用更持久的外键表示。在 django 中,它们被称为“自然键”。例如:

  • 使用 Permission.codename有利于使用 Permission.id
  • 使用 User.username有利于使用 User.id

阅读更多: “序列化 django 对象”中的自然键部分

Some other useful arguments for dumpdata:

  • --indent=4使其具有人类可读性。
  • -e sessions排除会话数据
  • -e admin排除管理站点上的管理操作历史
  • -e contenttypes -e auth.Permission排除了在 syncdb期间每次从模式中自动重新创建的对象。只能与 --natural一起使用它,否则您可能会得到对齐不好的 id 号。

我会给出另一个可能的答案。也许能帮到观察所,也许能帮到其他人。

我有一个多对多的关系表。它有一个主键和其他表的两个外键。我发现,如果 fixture 中有一个条目,其两个外键与表中已有的 与众不同pk 条目相同,那么它将失败。M2M 关系表对于两个外键有一个“唯一的一起”。

So, if it's a M2M relationship that is breaking, look at the foreign keys it's adding, look at your database to see if that pair of FKs are already listed under a different PK.

真的,真的很烦人. . 我每次都被咬。

I tried to dumpdata with --exclude contenttypes and --natural, I always get problems..

对我来说,最好的方法是在 syncdb 和 THEN 加载数据之后执行 truncate table django_content_type;

当然,对于 first _ data. json 自动加载来说,这是个陷阱。

I had encountered similar error sometimes ago. It turned out that I was trying to load the fixtures before creating the necessary tables. So I did:

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

And it worked like a charm

我没有使用 MySQL,而是将一些数据从一个活动服务器导入到 sqlite 中。在执行 loaddata之前清除 contenttypes应用程序的数据起到了作用:

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

And then

python manage.py loaddata data.json

这里的答案都很老套... ... 截至2017年,最好的答案是:

manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.Permission --indent 4
python manage.py dumpdata --natural-primary --exclude=contenttypes --exclude=auth.Permission --exclude=admin.logentry --exclude=sessions.session --indent 4 > initial_data.json

这对我很有用。这里我排除了除了实际模型之外的所有东西。

  • If you see any other model other than the models that you created you can safely exclude those. One drawback of this approach is you loose on log data as well as auth data.
./manage.py dumpdata app.Model --natural-foreign

将会改变

  "content_type": 123

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

现在 TestCase的夹具也可以用了

您需要使用自然键来表示任何外键和多对多关系。此外,在 sessions应用程序中排除 session表和 admin应用程序中排除 logentry表可能是一个好主意。

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

根据 姜戈文档--natural在版本1.7中已被弃用,因此应该使用选项 --natural-foreign

您还可以省略此对象的序列化数据中的主键,因为它可以在反序列化过程中通过传递 --natural-primary标志来计算。

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

姜戈2.2.5

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

帮助了我

在我的例子中,我已经转储了来自 auth(./manage.py dumpddata auth > fixtures/auth.json)的数据,以便将 fixture 用于测试目的。

开发继续进行,我删除了我在 models.py中定义的大部分模型,这时我开始看到这个恼人的问题。

我的解决方案是重新生成 auth.json 装置。这一个已经删除了大量的条目在 auth.permission相关的旧模型我有。

我尝试了上面的所有方法,都没用。我必须排除完整的认证模型,并且工作良好。

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

我通过添加我的测试 setUp 和 tearDown 来修复这个问题

from django.core import management

=====

def setUp(self):
management.call_command("loaddata", "all-data.yaml", verbosity=0)
super(login_page_test, self).setUp()


def tearDown(self):
management.call_command("flush", verbosity=0, interactive=False)
super(login_page_test, self).setUp()

我使用了 Pglader,只需要几秒钟就可以成功迁移:

$ pgloader project.load

project.load file with:

load database
from sqlite:////path/to/dev.db
into postgresql://user:pwd@localhost/db_name


with include drop, create tables, create indexes, reset sequences


set work_mem to '16MB', maintenance_work_mem to '512 MB';