我使用Factory boy作为我的模特。另一个模型有一个ForeignKey,该模型的第一个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'
我能做些什么来解决这个问题吗?就像在Factory_boy上覆盖模型A上的 str 方法一样?
答案 0 :(得分:0)
您遇到此类问题,因为A
模型实例的创建时间早于ReverseModel
实例。
正如factory_boy文档所说:
RelatedFactory:在构建/创建第一个Factory之后构建或创建一个给定的工厂。
请参阅http://factoryboy.readthedocs.io/en/latest/reference.html#post-generation-hooks
首先,您应该创建ReverseModel
,然后创建A
模型实例。
正如factory_boy文档在接收中所说:
当一个属性实际上是一个复杂的字段(例如,另一个Model的ForeignKey)时,请使用SubFactory声明
因此,您可以为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。