使用factory_boy测试Django应用时,模型实例未创建问题排查
问题分析与解决方案
从你给出的代码和报错信息来看,核心问题是**SomeFactory和AnotherFactory没有正确生成对应模型的实例**,反而把工厂类本身赋值给了self.some和self.another——这就是为什么你调用.delete()会报AttributeError,数据库查询为空,关联属性访问失败。
问题根源
你给SomeFactory和AnotherFactory添加的@create_attrs(values)装饰器是罪魁祸首:
- 这个装饰器要么是你自定义的,但实现逻辑破坏了factory_boy工厂类的实例化流程;要么是你误用了不存在的factory_boy内置装饰器(factory_boy并没有原生的
@create_attrs装饰器)。 - 被错误装饰后,调用
SomeFactory(...)不再返回SomeModel的实例,而是返回工厂类本身(也就是FactoryMetaClass类型),自然没有模型实例的.delete()方法,也不会写入数据库。
修复步骤
1. 移除或修正错误的装饰器
如果这个@create_attrs不是必须的,直接移除它,让工厂类回归正常的factory_boy用法:
import factory from factory.django import DjangoModelFactory from your_app.models import Study, SomeModel, AnotherModel, Group # 补全你代码中用到但未给出的GroupFactory class GroupFactory(DjangoModelFactory): class Meta: model = Group # 为Group模型添加必填字段,示例:name = factory.Faker("company") class StudyFactory(DjangoModelFactory): class Meta: model = Study group = factory.SubFactory(GroupFactory) # 添加Study模型的其他必填字段 # 移除@create_attrs装饰器,恢复正常工厂类定义 class SomeFactory(DjangoModelFactory): class Meta: model = SomeModel study = factory.SubFactory(StudyFactory) some_attr = "some attribute" # 添加SomeModel的其他必填字段 class AnotherFactory(DjangoModelFactory): class Meta: model = AnotherModel study = factory.SubFactory(StudyFactory) # 添加AnotherModel的其他必填字段
2. 验证测试用例的行为
修复工厂类后,你的测试用例setUp方法里的self.some = SomeFactory(study=self.study)会正确生成SomeModel的实例并写入数据库,此时:
.delete()方法可以正常调用- 数据库查询集能查到对应数据
- 关联属性(比如
self.some.study)可以正常访问
3. 如果需要自定义创建逻辑(替代@create_attrs)
如果你原本想用@create_attrs实现自定义属性逻辑,改用factory_boy内置的装饰器:
- 用
@factory.lazy_attribute动态生成属性值:class SomeFactory(DjangoModelFactory): class Meta: model = SomeModel study = factory.SubFactory(StudyFactory) @factory.lazy_attribute def some_attr(self): # 自定义逻辑生成属性值 return f"attr_for_study_{self.study.id}" - 用
@factory.post_generation处理创建后的额外操作:class SomeFactory(DjangoModelFactory): class Meta: model = SomeModel study = factory.SubFactory(StudyFactory) some_attr = "some attribute" @factory.post_generation def post_create(self, create, extracted, **kwargs): if not create: return # 实例创建后的额外操作,比如关联其他对象 self.some_related_field = SomeOtherFactory() self.save()
额外提醒
- 确保所有工厂类的
Meta.model都指向正确的Django模型类 - 如果模型有必填字段,工厂类里必须为这些字段提供默认值或通过
SubFactory关联生成
内容的提问来源于stack exchange,提问作者Ryan Skene
相关产品推荐
相关产品推荐

