Django使用Factory boy创建SubFactory时报User无profile错误如何解决
问题原因
核心是ProfileFactory和UserFactory的循环依赖搭配SubFactory的传参冲突,导致User实例创建后没有关联对应的Profile实例,具体执行路径如下:
- 调用
LabelFactory.create()时,首先解析profile = factory.SubFactory(ProfileFactory)触发Profile实例创建 - ProfileFactory执行时解析
user = factory.SubFactory("releases.factories.UserFactory", profile=None),触发User实例创建,同时显式传入profile=None参数 - factory_boy规则下,给UserFactory传入
profile=None会自动跳过UserFactory上定义的profile = factory.RelatedFactory(ProfileFactory)逻辑,不会自动创建关联的Profile - 后续只要有逻辑(比如模型的
__str__方法、clean方法、工厂后置钩子)访问user.profile属性,就会抛出RelatedObjectDoesNotExist错误
静音post_save信号是辅助诱因:如果你的项目原本配置了User创建后自动生成Profile的post_save信号,静音后该逻辑也不会生效。
解决方法
两种方案二选一即可:
方案1:移除SubFactory的多余参数
你传入profile=None的本意是避免循环创建,实际上factory_boy已经原生处理了一对一关联的循环依赖场景,直接删掉该参数即可:
@factory.django.mute_signals(post_save) class ProfileFactory(factory.django.DjangoModelFactory): class Meta: model = Profile # 删除profile=None传参即可 user = factory.SubFactory("releases.factories.UserFactory")
修改后RelatedFactory生成的Profile实例会和上层的ProfileFactory实例复用,不会重复创建。
方案2:重构工厂逻辑避免循环绑定
如果想要更清晰的依赖关系,可以调整工厂定义,移除UserFactory上的RelatedFactory:
@factory.django.mute_signals(post_save) class UserFactory(factory.django.DjangoModelFactory): class Meta: model = User email = factory.Faker("email") password = factory.Faker("password") # 移除此处的RelatedFactory定义 @factory.django.mute_signals(post_save) class ProfileFactory(factory.django.DjangoModelFactory): class Meta: model = Profile user = factory.SubFactory("releases.factories.UserFactory") # LabelFactory无需修改
如果你的项目本身就靠post_save信号自动创建User对应的Profile,直接移除两个工厂的@factory.django.mute_signals(post_save)装饰器即可,不需要额外配置关联逻辑。
内容的提问来源于stack exchange,提问作者Adilet Usonov
相关产品推荐
相关产品推荐

