如何在SQLAlchemy声明式模型中正确配置FactoryBoy SubFactory?
解决FactoryBoy SubFactory与SQLAlchemy外键关联的适配问题
这个问题我之前也碰到过,核心原因是你把SubFactory返回的Group模型对象直接赋值给了需要整数ID的group_id字段,SQLAlchemy没法把对象转换成数据库能识别的整数类型,所以才会抛出can't adapt type 'Group'的错误。下面给你两种解决思路,以及修正后的完整代码:
一、先修正SQLAlchemy模型(补充必要配置)
首先确保模型指定了表名,同时推荐补充ORM关系字段(方便后续关联查询,也能让FactoryBoy更好地处理关联):
from sqlalchemy import Column, Integer, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship Base = declarative_base() # 注意统一变量名大小写,避免拼写错误 class Group(Base): __tablename__ = "groups" # 必须指定表名,避免SQLAlchemy自动生成的表名出现问题 group_id = Column(Integer, autoincrement=True, primary_key=True) # 补充反向关联字段,方便从Group查询关联的Person people = relationship("Person", back_populates="group") class Person(Base): __tablename__ = "people" person_id = Column(Integer, autoincrement=True, primary_key=True) group_id = Column(Integer, ForeignKey(Group.group_id)) # 补充正向关联字段,方便从Person获取关联的Group对象 group = relationship("Group", back_populates="people")
二、两种正确的Factory配置方式
方式1:利用ORM关系字段赋值(推荐)
直接给Person模型的关系字段group赋值SubFactory,FactoryBoy会自动处理外键group_id的填充:
import factory from factory.alchemy import SQLAlchemyModelFactory from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from your_module import Base, Person, Group # 配置Factory使用的数据库Session engine = create_engine("postgresql://your_user:your_password@your_host/your_db") # 替换为你的数据库连接串 Session = sessionmaker(bind=engine) db_session = Session() # 定义基础Factory类,统一配置Session class BaseFactory(SQLAlchemyModelFactory): class Meta: model = Base sqlalchemy_session = db_session sqlalchemy_session_persistence = "commit" # 测试场景也可以用"rollback"避免污染数据库 class GroupFactory(BaseFactory): class Meta: model = Group class PersonFactory(BaseFactory): class Meta: model = Person # 直接给关系字段group赋值SubFactory,FactoryBoy会自动生成Group并填充group_id group = factory.SubFactory(GroupFactory)
方式2:直接生成外键ID值
如果你不想依赖ORM关系字段,可以通过LazyAttribute从SubFactory生成的对象中提取ID:
class PersonFactory(BaseFactory): class Meta: model = Person # 先生成Group实例,再提取它的group_id赋值给字段 group_id = factory.LazyAttribute(lambda _: GroupFactory().group_id)
三、测试代码的正确用法
现在运行测试代码就不会报错了:
from your_module import PersonFactory # 创建Person时会自动创建关联的Group,并正确填充group_id person = PersonFactory.create() print(person.group_id) # 输出关联Group的ID print(person.group) # 如果用方式1配置了关系字段,这里会返回对应的Group对象
内容的提问来源于stack exchange,提问作者Ben Liyanage
相关产品推荐
相关产品推荐

