8

如何在 Django 单元测试中使用 GenericRelations?

我在互联网上阅读并尝试了无数建议,但无济于事。

在 Django 中加载固定装置时,这是有希望的

但是 Django 1.6 中不再存在“重置”命令

我的项目对 ContentType 使用 GenericForeign 键,对 auth.Users 使用外键。我使用 --natural 选项仅为我的应用程序转储了数据,但这会导致测试数据库中不存在用户的问题。现在我删除了 --natural 选项,而是转储了所有 3 个应用程序 myApp、auth、contenttypes 的数据。当我运行测试时,我得到“无法加载 contenttypes.ContentType(pk=50): columns app_label, model are not unique”。我认为这是由于导入模型时动态创建的内容类型。

使用的命令:

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

接下来我转储了 myApp,auth 离开了 contenttypes。我认为由于 ContentTypes app db 是动态创建的,并且我的灯具具有自然键,所以这应该可以工作。它没有。

现在我得到:

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

如何让带有 contetypes 的固定器工作?在测试中使用设置和创建对象会更好吗?

4

3 回答 3

5

使用content_type: [<app_label>, <model>],代替content_type: <hard-coded pk of model>

于 2017-04-24T13:13:54.117 回答
2

我意识到这个问题被问到已经一年多了,但是您(或其他人)可能想知道我能够使用固定装置来测试具有 ContentType 通用外键的模型。不过,有一个警告,那就是我必须在测试装置中硬编码 content_type_id,而且就在数据库中创建 ContentTypes 的顺序而言,这可能有点不稳定。(由于@Lara 提到的原因,我开始用 factory_boy 重写我的测试)

我目前正在使用 Django 1.8.3、Python 2.7.9。

关键特征似乎是加载固定装置的顺序。在我的 tests.py 中,我有:

测试.py:

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

    def test_something(self):
        # your tests

上面,gfk_model.json 包含模型的固定装置,该模型包含 ContentType 的通用外键。my_model.json 包含您的 Django 项目或应用程序需要的任何模型的固定装置。所以我首先实例化包含通用外键的模型实例。确实,他们的 object_id 条目引用了 my_model 的数据库行,这些行还不完全存在,但一旦加载 my_model.json 固定装置就会存在。

我的模型/模型.py

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

GFKModel/models.py

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

如果我将通用外键与一个特定的 ContentType 相关联,那么我可以从 SQL 数据库中获取内容类型的 id,或者content_type_id = ContentType.objects.get_for_model(MyModel).pk在 django shell ( python manage.py shell) 中执行。然后我在我的灯具中硬编码(yukky 我知道!)因此获得的 id(在我的情况下为 13)。

所以,最后固定装置(从转储数据中获得,然后编辑)看起来像这样

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

[
{
  "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", 
  }
}
]

在 gfk_model.json 中,object_id 1 和 2 分别对应 my_model.json 的 PK 1、2。我也为 gkf_model 实例提供了 PK(尽管我可能不需要,也没有尝试删除它们)。

总而言之,让它工作起来实际上比写这篇文章要快得多!

仅通过在测试 setUp() 中使用 ORM 来让 GFK 测试正常工作也非常简单。factory_boy 也很好。

如果您有几个不同的 ContentType,尤其是如果它们可能会更改它们在 contenttypes 表中的 pk,我认为固定装置不会非常成功。

于 2015-08-26T22:54:53.157 回答
-4

不应该使用固定装置有几个原因:

  • 很慢
  • 很难更新/维护;
  • 不是练习;

而不是固定装置,您应该使用像 factory boy 这样的“模拟”应用程序:

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

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

于 2014-07-11T12:07:37.537 回答