您可以覆盖 factory_boy 的模型函数吗?

Can you override a model function for factory_boy?

我正在为我的模型使用 Factory boy。另一个模型有一个外键,该模型的第一个 obj 用于模型的字符串表示。示例结构:

class A(models.Model):
    ...

    def __str__(self):
    return self.reverseForeignKey_set.first().name

class AFactory(factory.django.DjangoModelFactory):

    class Meta:
        model = models.A

    some_attribute = factory.RelatedFactory(
        ReverseModelFactory,
        'a',
        )

但是当我使用factory_boy创建时,它给我这个错误:

Traceback (most recent call last):
  File "/home/rahul/Documents/projects/healbot_current/healbot/functional_tests/tests.py", line 21, in setUp
    factories.AFactory.create()
  File "/home/rahul/Envs/healbot/lib/python3.6/site-packages/factory/base.py", line 623, in create
    return cls._generate(True, attrs)
  File "/home/rahul/Envs/healbot/lib/python3.6/site-packages/factory/base.py", line 554, in _generate
    results[name] = decl.call(obj, create, extraction_context)
  File "/home/rahul/Envs/healbot/lib/python3.6/site-packages/factory/declarations.py", line 624, in call
    return factory.simple_generate(create, **passed_kwargs)
  File "/home/rahul/Envs/healbot/lib/python3.6/site-packages/factory/base.py", line 709, in simple_generate
    return cls.generate(strategy, **kwargs)
  File "/home/rahul/Envs/healbot/lib/python3.6/site-packages/factory/base.py", line 676, in generate
    return action(**kwargs)
  File "/home/rahul/Envs/healbot/lib/python3.6/site-packages/factory/base.py", line 622, in create
    attrs = cls.attributes(create=True, extra=kwargs)
  File "/home/rahul/Envs/healbot/lib/python3.6/site-packages/factory/base.py", line 449, in attributes
    utils.log_repr(extra),
  File "/home/rahul/Envs/healbot/lib/python3.6/site-packages/factory/utils.py", line 142, in log_repr
    return compat.force_text(repr(obj))
  File "/home/rahul/Envs/healbot/lib/python3.6/site-packages/django/db/models/base.py", line 588, in __repr__
    u = six.text_type(self)
  File "/home/rahul/Documents/projects/healbot_current/healbot/diagnosis/models.py", line 57, in __str__
    return self.reverseForeignKey_set.first().name
AttributeError: 'NoneType' object has no attribute 'name'

有什么办法可以解决这个问题吗?就像重写模型 A 上的 str 方法只是为了 factory_boy?

您遇到这样的问题是因为 A 模型实例的创建时间早于 ReverseModel 实例的创建时间。

正如 factory_boy 文档所说:

RelatedFactory: this builds or creates a given factory after building/creating the first Factory.

http://factoryboy.readthedocs.io/en/latest/reference.html#post-generation-hooks

首先,您应该创建 ReverseModel,然后是 A 模型实例。 正如 factory_boy 文档在收据中所说:

When one attribute is actually a complex field (e.g a ForeignKey to another Model), use the SubFactory declaration

因此您可以为您的 FK 模型定义一个工厂,并将其定义为 AFactory 中的 SubFactory。

# models.py
class A(models.Model):
    ...

    def __str__(self):
        return self.reverseForeignKey_set.first().name

# factories.py
import factory
from . import models

class ReverseModelFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.ReverseModel

        # Define your model fields
        attr = factory.Faker('text', max_nb_chars=255)

class AFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.A

    some_attribute = factory.SubFactory(ReverseModelFactory)

在这种情况下,您的 ReverseModelFactory 对象将首先创建,这应该可以解决您的问题。 有关详细信息,请参阅 http://factoryboy.readthedocs.io/en/latest/recipes.html

我还应该注意,如果你想处理 ManyToMany 字段,你应该使用 post_generation 钩子:

# models.py
class Group(models.Model):
    name = models.CharField()

class User(models.Model):
    name = models.CharField()
    groups = models.ManyToManyField(Group)


# factories.py
class GroupFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Group

    name = factory.Sequence(lambda n: "Group #%s" % n)

class UserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.User

    name = "John Doe"

    @factory.post_generation
    def groups(self, create, extracted, **kwargs):
        if not create:
            # Simple build, do nothing.
            return

        if extracted:
            # A list of groups were passed in, use them
            for group in extracted:
                self.groups.add(group)

有关详细信息,请参阅 http://factoryboy.readthedocs.io/en/latest/recipes.html#simple-many-to-many-relationship