如何为Factory Boy动态指定Django数据库
解决Factory Boy动态指定数据库的方案
我之前在做多数据库Django项目测试的时候,也被这个问题卡过一阵——总不能每个数据库都写个重复的Factory吧?后来摸索出几个实用的办法,不用重复造轮子就能动态切换数据库:
方法1:重写Factory的create方法,支持using参数
这种方式最直接,给Factory加一个可选的using参数,创建实例后指定数据库保存:
from factory.django import DjangoModelFactory class BaseDynamicDBFactory(DjangoModelFactory): class Meta: abstract = True # 标记为抽象基类,不会被直接实例化 @classmethod def create(cls, **kwargs): # 从kwargs中取出using参数,默认用default数据库 db_alias = kwargs.pop('using', 'default') # 先创建实例 instance = super().create(**kwargs) # 指定数据库保存 instance.save(using=db_alias) return instance # 你的业务模型Factory继承这个基类 class MyModelFactory(BaseDynamicDBFactory): class Meta: model = MyModel # 这里定义你的模型字段工厂,比如: name = factory.Faker('company')
使用的时候直接传using参数就行:
# 往db1数据库创建实例 instance_db1 = MyModelFactory.create(using='db1') # 往db2数据库创建实例 instance_db2 = MyModelFactory.create(using='db2')
方法2:动态指定Manager的数据库别名
Factory Boy默认用模型的objects管理器,我们可以重写_get_manager方法,让它根据参数动态选择数据库:
class MyModelFactory(DjangoModelFactory): class Meta: model = MyModel @classmethod def _get_manager(cls, model_class): # 优先从kwargs取using,没有就用default using = cls._creation_kwargs.get('using', 'default') return model_class.objects.using(using) @classmethod def create(cls, **kwargs): # 临时保存using参数,供_get_manager使用 cls._creation_kwargs = kwargs try: return super().create(**kwargs) finally: # 用完清空,避免影响后续创建 delattr(cls, '_creation_kwargs')
使用方式和上面一样:
MyModelFactory.create(using='your_db_alias')
方法3:利用Factory Boy的Params定义可选参数
这种方式更贴合Factory Boy的设计风格,用Params来声明可选的数据库参数,然后在_create方法里使用:
class MyModelFactory(DjangoModelFactory): class Meta: model = MyModel # 定义可选参数,默认用default数据库 class Params: using = 'default' @classmethod def _create(cls, model_class, *args, **kwargs): # 取出using参数,优先用传入的值,没有就用Params默认值 using = kwargs.pop('using', cls.Params.using) # 指定数据库的管理器创建实例 return model_class.objects.using(using).create(*args, **kwargs)
使用起来同样简单:
MyModelFactory.create(using='db3')
注意事项
- 如果你的测试用了Django的事务测试框架,要确保每个数据库的事务配置正确,避免出现数据隔离问题;
- 要是有多个模型都需要动态选库,推荐用方法1的抽象基类,所有业务Factory继承它就行,不用重复写逻辑;
内容的提问来源于stack exchange,提问作者eLRuLL
相关产品推荐
相关产品推荐

