You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级Django至2.2后Factory Boy的post_generation钩子无法设置模型属性

解决Factory Boy动态属性丢失的AttributeError问题

嘿,这个问题我升级Django 2.2的时候也踩过坑!来给你捋捋原因和解决办法:

问题根源

你碰到的AttributeError: 'ModelA' object has no attribute 'post_generated_objs'主要有这几个原因:

  • 你的ModelA数据库模型里并没有定义post_generated_objs字段,这个属性是通过Factory Boy的post_generation钩子动态添加到实例内存中的,并没有持久化到数据库。
  • 升级Django 2.2后,当Factory Boy以create=True模式创建ModelA实例(也就是保存到数据库),后续如果ORM重新从数据库加载这个实例(比如FactoryB中访问obj.model_a时),动态添加的属性会直接丢失——因为数据库里根本没有这个字段,重新加载的实例自然不会携带它。
  • 另外,Factory Boy的post_generation钩子是在实例保存到数据库之后才运行的,这意味着你设置的属性只存在于当时的内存实例上,一旦实例被刷新(比如调用refresh_from_db()),属性就没了。

可行的解决方案

方案1:修改ModelA,预初始化属性(简单直接)

在ModelA的__init__方法里预先初始化这个属性,这样不管实例是新建的还是从数据库加载的,都会有这个属性,不会触发AttributeError:

from django.db import models

class ModelA(models.Model):
    name = models.CharField(max_length=255)  # 你的现有字段

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 预先初始化属性,避免不存在的情况
        self.post_generated_objs = []

方案2:利用Factory Boy的_results=True(无需改动模型)

如果你不想修改业务模型代码,可以用Factory Boy SubFactory的_results=True参数,直接捕获post_generation钩子返回的对象,完全绕开依赖模型实例属性的问题:

class FactoryA(factory.django.DjangoModelFactory):
    class Meta:
        model = ModelA
    name = 'John'

    @factory.post_generation
    def post_hook(self, create, extracted, **kwargs):
        post_generated_objs = []
        for i in range(3):
            post_generated_objs.append(SomeOtherFactory(id=i+100))
        # 这里依然可以设置属性,但我们后续不会依赖它
        self.post_generated_objs = post_generated_objs
        # 关键:返回这些对象,后续通过SubFactory的结果获取
        return post_generated_objs

class FactoryB(factory.django.DjangoModelFactory):
    class Meta:
        model = ModelB

    # 使用_results=True,同时获取SubFactory创建的实例和post_generation的返回值
    model_a, post_generated_objs = factory.SubFactory(FactoryA, _results=True)

    # 直接用捕获到的返回值,而不是从model_a实例读取
    some_data = factory.LazyAttribute(lambda obj: obj.post_generated_objs[0])

这个方案更优雅,完全在测试工厂层解决问题,不需要改动业务模型,尤其适合测试场景下的临时数据关联。

另外,我注意到你的FactoryB代码里写的是obj.model_a.post_generated_objects[0],而FactoryA里设置的是post_generated_objs——如果这是笔误的话,也要记得修正哦!

内容的提问来源于stack exchange,提问作者Sudhanshu Mishra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:15:05