简体   繁体   English

Django测试和ContentType通用关联夹具

[英]Django testing and ContentType generic relatations fixtures

How do I use GenericRelations in Django unit testing? 如何在Django单元测试中使用GenericRelations?

I have read and tried countless suggestions on the internets to no avail. 我已阅读并尝试了无数的互联网建议无济于事。

This one was promising Problems with contenttypes when loading a fixture in Django 这个有希望在Django中加载一个fixture时有内容类型的问题

but "reset" command is no longer there in Django 1.6 但Django 1.6中不再出现“reset”命令

My project uses GenericForeign key to ContentType and a Foreign key to auth.Users. 我的项目使用GenericForeign键作为ContentType,使用外键作为auth.Users。 I dumped the data only for my app using the --natural option but this lead to the problem where users didn't exist in the test database. 我使用--natural选项仅为我的应用程序转储数据,但这会导致测试数据库中不存在用户的问题。 Now I removed the --natural option and instead dumped data for all 3 apps myApp, auth, contenttypes. 现在我删除了--natural选项,而是转储了所有3个应用程序myApp,auth,contenttypes的数据。 When I'm running the test I get "Could not load contenttypes.ContentType(pk=50): columns app_label, model are not unique". 当我运行测试时,我得到“无法加载contenttypes.ContentType(pk = 50):列app_label,模型不是唯一的”。 I think this is due to the contenttypes being created dynamically when models are imported. 我认为这是由于在导入模型时动态创建了contenttypes。

The command used: 使用的命令:

python manage.py dumpdata auth myApp contenttypes --natural --indent=4 > auhtmtmnatural.json

Next I dumped myApp, auth leaving off contenttypes. 接下来我转储了myApp,auth离开了contenttypes。 I figured that since ContentTypes app db is created dynamically and my fixtures have natural keys, this should work. 我认为,由于ContentTypes app db是动态创建的,而我的灯具有自然键,这应该可行。 It doesn't. 它没有。

Now I'm getting: 现在我得到:

DeserializationError: Problem installing fixture 'auhtmtmnatural.json': ContentType matching query does not exist.

How do I get fixutres with contetypes to work? 如何使用contetypes工作? Is it better to use setup and create objects in testing? 在测试中使用设置和创建对象是否更好?

使用content_type: [<app_label>, <model>],而不是content_type: <hard-coded pk of model>

I realise it's more than a year since this question was asked, however you (or someone else) might like to know that I was able to use fixtures in testing a model with generic foreign key to ContentType. 我意识到这个问题被问了一年多,但是你(或其他人)可能想知道我能够使用fixture来测试具有ContentType的通用外键的模型。 There's a caveat to this though, which is that I had to hard-code the content_type_id in the test fixtures, and that is probably a bit unstable in terms of order in which ContentTypes are created in the database. 但是有一个警告,那就是我必须在测试装置中对content_type_id进行硬编码,这在数据库中创建ContentTypes的顺序方面可能有点不稳定。 (I'm beginning to re-write my tests with factory_boy for the reasons @Lara mentioned) (由于@Lara提到的原因,我开始用factory_boy重新编写我的测试)

I am currently using Django 1.8.3, Python 2.7.9. 我目前正在使用Django 1.8.3,Python 2.7.9。

The key feature seems to be the order of loading fixtures. 关键特征似乎是装载夹具的顺序。 In my tests.py I have: 在我的tests.py中我有:

tests.py: tests.py:

class MyModelViewTests(TestCase):
    fixtures = [
        'auth_user.json',
        'gfk_model.json',
        'my_model.json',
    ]

    def test_something(self):
        # your tests

Above, the gfk_model.json contains fixtures for the model containing the generic foreign key to ContentType. 上面,gfk_model.json包含包含ContentType的通用外键的模型的fixture。 The my_model.json contains the fixtures for whatever model your Django project or app needs. my_model.json包含Django项目或应用程序所需的任何模型的fixture。 So I instantiate the model instances containing generic foreign keys first. 所以我首先实例化包含通用外键的模型实例。 It's true that their object_id entries reference database rows for my_model which don't quite exist yet, but will exist as soon as the my_model.json fixtures are loaded. 确实,他们的object_id条目引用了my_model的数据库行,这些行尚未存在,但是一旦加载了my_model.json灯具就会存在。

MyModel/models.py 为MyModel / models.py

class MyModel(models.Model):
    book_title = models.TextField()
    book_isbn = models.CharField(max_length=13)

GFKModel/models.py GFKModel / models.py

class GFKModel(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey()
    your_field = models.TextField()

If I'm associating the generic foreign key with one particular ContentType, then I can get the id of the content type from the SQL database or content_type_id = ContentType.objects.get_for_model(MyModel).pk , executed in a django shell ( python manage.py shell ). 如果我将通用外键与一个特定的ContentType相关联,那么我可以从SQL数据库中获取内容类型的id或者在django shell中执行的content_type_id = ContentType.objects.get_for_model(MyModel).pkpython manage.py shell )。 I then hardcoded (yukky I know!) the id thus obtained (13 in my case) in my fixtures. 然后,我在我的灯具中硬编码(yukky,我知道!)这样获得的id(在我的情况下为13)。

So, finally the fixtures (obtained from dumpdata, then edited) look something like this 所以,最后的灯具(从dumpdata获得,然后编辑)看起来像这样

gfk_model.json gfk_model.json

[
{
    "fields": {
        "your_field": "Stuff you need to associate with my_model",
        "object_id": 1,
        "content_type": 13,
    },
    "model": "myapp.gfk_model",
    "pk": 1
},
{
    "fields": {
        "your_field": "Stuff you need to associate with my_model",
        "object_id": 2,
        "content_type": 13,
    },
    "model": "gfk_app.gfk_model",
    "pk": 2
}
]

my_model.json my_model.json

[
{
  "pk": 1, 
  "model": "myapp.my_model", 
  "fields": {
    "book_name": "How to bath your cat", 
    "book_isbn": "123456", 
  }
},
{
  "pk": 2, 
  "model": "myapp.my_model", 
  "fields": {
    "book_name": "How About Wednesday?", 
    "book_isbn": "654321", 
  }
}
]

In the gfk_model.json the object_id of 1 and 2 correspond to the PKs 1, 2 of the my_model.json respectively. 在gfk_model.json中,object_id为1和2分别对应于my_model.json的PKs 1,2。 I've provided PKs for the gkf_model instances too (although possibly I don't need to, haven't tried removing them). 我也为gkf_model实例提供了PK(虽然可能我不需要,但没有尝试删除它们)。

All in all, it was actually much quicker to get it working than to write this post! 总而言之,它实际上比写这篇文章要快得多!

It's also pretty straightforward to get GFK tests working just by using the ORM in the test setUp(). 通过在测试setUp()中使用ORM,使GFK测试正常工作也非常简单。 Also fine with factory_boy too. 也很好用factory_boy。

If you've got several different ContentTypes, and especially if they are likely to change their pk in the contenttypes table, I don't think fixtures are going to be very successful. 如果你有几个不同的ContentTypes,特别是如果他们可能在contenttypes表中改变他们的pk,我认为固定装置不会非常成功。

There are several reasons why you shouldn't use fixtures: 你不应该使用灯具有几个原因:

  • It's slow 这很慢
  • It's hard to update/maintain; 更新/维护很难;
  • Is not practice; 不练习;

Instead of fixtures you should use a "mock" app like factory boy: 你应该使用像工厂男孩这样的“模拟”应用程序而不是固定装置:

http://factoryboy.readthedocs.org/en/latest/ http://factoryboy.readthedocs.org/en/latest/

https://pypi.python.org/pypi/factory_boy/ https://pypi.python.org/pypi/factory_boy/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM