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

如何使用factory_boy为Django含筛选多对多字段的模型编写工厂类?

嘿,我来帮你搞定这个factory_boy工厂类的编写问题!针对你带筛选条件的同模型多对多字段,咱们一步步来实现:

第一步:先搞定依赖模型的工厂

首先,你的Places模型依赖User、Place,还有Place关联的Site模型(从limit_choices_to={'site__token': 'site1'}能看出来),所以得先给这些模型写基础工厂:

import factory
from django.contrib.auth import get_user_model
from .models import Site, Place, Places

# 拿到User模型(兼容自定义User)
User = get_user_model()

# Site模型的工厂
class SiteFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Site

    # 默认生成随机token,同时定义子类专门生成site1的实例
    token = factory.Faker('word')

    class Site1Factory(SiteFactory):
        token = 'site1'

# Place模型的工厂
class PlaceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Place

    # 默认关联随机Site,同样定义子类生成属于site1的Place
    site = factory.SubFactory(SiteFactory)
    name = factory.Faker('company')  # 示例字段,替换成你实际的字段

    class Site1PlaceFactory(PlaceFactory):
        site = factory.SubFactory(SiteFactory.Site1Factory)

# User模型的工厂
class UserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = User

    username = factory.Faker('user_name')
    email = factory.Faker('email')

第二步:编写Places模型的核心工厂

这里重点处理带筛选条件的多对多字段place1和place2,用factory.post_generation装饰器来处理多对多关联(因为多对多需要主实例创建后才能添加关联):

class PlacesFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Places

    # 关联User实例
    user = factory.SubFactory(UserFactory)

    # 处理place1字段:只能关联site__token='site1'的Place
    @factory.post_generation
    def place1(self, create, extracted, **kwargs):
        # 如果是build模式(不写入数据库),直接返回
        if not create:
            return

        # 如果你手动传入了place1的实例列表,就用你传入的
        if extracted:
            for place in extracted:
                self.place1.add(place)
        else:
            # 默认自动创建2个符合条件的site1 Place实例并关联
            site1_places = PlaceFactory.Site1PlaceFactory.create_batch(2)
            self.place1.add(*site1_places)

    # 同理处理place2字段(假设它的筛选条件是site__token='site2',你可以按需修改)
    @factory.post_generation
    def place2(self, create, extracted, **kwargs):
        if not create:
            return

        if extracted:
            for place in extracted:
                self.place2.add(place)
        else:
            # 先定义site2的Site工厂子类,再生成对应的Place
            class Site2Factory(SiteFactory):
                token = 'site2'

            class Site2PlaceFactory(PlaceFactory):
                site = factory.SubFactory(Site2Factory)

            site2_places = Site2PlaceFactory.create_batch(2)
            self.place2.add(*site2_places)

怎么用这个工厂?

  • 默认创建:PlacesFactory() 会自动生成关联的User、2个site1的Place给place1、2个site2的Place给place2
  • 手动指定关联:my_site1_place = PlaceFactory.Site1PlaceFactory(),然后PlacesFactory(place1=[my_site1_place])

这样写的好处是,既遵守了模型里limit_choices_to的筛选规则,又保持了工厂的灵活性,你既可以让工厂自动生成符合条件的实例,也能手动传入指定的实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:25:25