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

FactoryBoy中post_generation无法访问关联模型对象的问题

解决FactoryBoy中Questionnaire关联Question与Dimension的分配问题

先明确模型结构(基于你的描述)

# models.py
from django.db import models

class Dimension(models.Model):
    name = models.CharField(max_length=100)

class Questionnaire(models.Model):
    title = models.CharField(max_length=200)
    dimensions = models.ManyToManyField(Dimension, blank=True)

class Question(models.Model):
    text = models.CharField(max_length=200)
    questionnaire = models.ForeignKey(Questionnaire, on_delete=models.CASCADE, related_name='question_set')
    dimension = models.ForeignKey(Dimension, on_delete=models.SET_NULL, null=True, blank=True)

核心问题分析

  1. post_generation中question_set为空:Trait里用RelatedFactory创建的Question是在Questionnaire保存后才生成的,而post_generation钩子执行时,Question还未创建,所以self.question_set.all()返回空。
  2. Trait中直接设置Question.dimension失败:创建Question时,Questionnaire的dimensions多对多关系还未建立(或Dimension未添加),无法获取可用的Dimension对象。

解决方案1:在Question工厂中添加钩子自动分配Dimension

这种方式最灵活,能确保Question创建后自动从关联Questionnaire的dimensions中随机选一个分配:

# factories.py
import factory
import random
from factory.django import DjangoModelFactory
from .models import Dimension, Questionnaire, Question

class DimensionFactory(DjangoModelFactory):
    class Meta:
        model = Dimension
    name = factory.Faker('word')

class QuestionFactory(DjangoModelFactory):
    class Meta:
        model = Question
    text = factory.Faker('sentence')
    questionnaire = factory.SubFactory(QuestionnaireFactory)

    @factory.post_generation
    def auto_assign_dimension(self, create, extracted, **kwargs):
        if not create:
            return
        # 从关联问卷的维度列表中随机选一个分配
        available_dims = list(self.questionnaire.dimensions.all())
        if available_dims:
            self.dimension = random.choice(available_dims)
            self.save()

class QuestionnaireFactory(DjangoModelFactory):
    class Meta:
        model = Questionnaire
    title = factory.Faker('sentence')

    # 批量添加维度的钩子
    @factory.post_generation
    def dimensions(self, create, extracted, **kwargs):
        if not create:
            return
        if extracted:
            self.dimensions.add(*extracted)

    # 带问题的Trait
    class Trait:
        with_questions = factory.Trait(
            question_set=factory.RelatedFactoryList(
                QuestionFactory,
                size=3,
                factory_related_name='questionnaire'
            )
        )

使用示例

# 先创建维度,再创建带维度和问题的问卷
dim1 = DimensionFactory()
dim2 = DimensionFactory()
questionnaire = QuestionnaireFactory(with_questions=True, dimensions=[dim1, dim2])

# 验证每个问题都分配了维度
for question in questionnaire.question_set.all():
    assert question.dimension in [dim1, dim2]

解决方案2:自定义Trait同时创建维度和问题

如果需要一次性创建带维度和关联问题的问卷,可以写一个自定义Trait,确保维度先被添加,再创建问题并分配:

class QuestionnaireFactory(DjangoModelFactory):
    class Meta:
        model = Questionnaire
    title = factory.Faker('sentence')

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        instance = super()._create(model_class, *args, **kwargs)
        # 检查是否启用了带维度和问题的Trait
        if kwargs.get('with_dims_and_questions'):
            # 创建指定数量的维度并添加到问卷
            dim_count = kwargs.get('dim_count', 2)
            dimensions = DimensionFactory.create_batch(dim_count)
            instance.dimensions.add(*dimensions)
            # 创建问题并随机分配维度
            q_count = kwargs.get('question_count', 3)
            for _ in range(q_count):
                QuestionFactory(
                    questionnaire=instance,
                    dimension=random.choice(dimensions)
                )
        return instance

    class Trait:
        with_dims_and_questions = factory.Trait()

使用示例

# 创建带2个维度、3个问题的问卷,每个问题自动分配维度
questionnaire = QuestionnaireFactory(with_dims_and_questions=True, dim_count=2, question_count=3)

关键注意事项

  • RelatedFactory/RelatedFactoryList创建的关联对象晚于主对象保存,所以主对象的post_generation钩子无法直接获取到这些关联对象。
  • 要访问主对象的多对多字段,必须确保多对多关系在关联对象创建前就已建立,或者在关联对象的post_generation钩子中处理(此时主对象已完全创建,多对多字段可访问)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:00:00