如何用Factory Boy让User、Profile、UserPhoto共享同一用户生成测试数据
问题:批量生成用户时自动创建关联的UserPhoto
我用假数据填充数据库,拥有User、Profile、UserPhoto三个独立模型,其中UserPhoto通过ForeignKey关联User。当前调用ProfileFactory.create_batch(10)可生成10个用户及对应的Profile,但我希望同时为每个用户生成2张UserPhoto(总计20张),且所有模型都关联同一用户数据。现有UserPhotoFactory的user字段配置存在疑问,请问如何调整代码实现该需求?
现有Factory代码
class UserFactory(DjangoModelFactory): class Meta: model = User email = factory.Faker('email') first_name = factory.Faker('first_name') birthday = factory.Faker('date_object') age = factory.Faker('pyint', min_value=18, max_value=100) is_staff = False is_active = True class UserPhotoFactory(DjangoModelFactory): class Meta: model = UserPhoto user = factory.RelatedFactory(UserFactory) # 此处配置有问题 order = factory.Faker('pyint', min_value=0, max_value=4) url = factory.Faker( 'random_element', elements=[x for x in ['https://picsum.photos/seed/picsum/200/300', 'https://picsum.photos/seed/pssss/200/300', 'https://picsum.photos/seed/picwum/200/300']] ) class ProfileFactory(DjangoModelFactory): class Meta: model = Profile user = factory.SubFactory(UserFactory) bio = factory.LazyAttribute(lambda o: FAKE.paragraph(nb_sentences=5, ext_word_list=['abc', 'def', 'ghi', 'jkl']))
UserPhoto模型定义
class UserPhoto(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) order = models.PositiveIntegerField(null=True) url = models.CharField(max_length=220)
解决方案
1. 修正UserPhotoFactory的user字段配置
原代码中factory.RelatedFactory(UserFactory)用法错误,RelatedFactory是从父模型生成子模型,而非反向关联。这里应将UserPhoto的user字段设为factory.SubFactory(UserFactory),作为默认值方便单独创建照片,批量生成时会自动被关联的User覆盖。
2. 在UserFactory中添加批量生成UserPhoto的逻辑
使用factory.RelatedFactoryList让每个User创建时自动生成指定数量的UserPhoto,确保关联关系正确。
修改后的完整Factory代码
class UserFactory(DjangoModelFactory): class Meta: model = User email = factory.Faker('email') first_name = factory.Faker('first_name') birthday = factory.Faker('date_object') age = factory.Faker('pyint', min_value=18, max_value=100) is_staff = False is_active = True # 每个用户自动生成2张关联照片 photos = factory.RelatedFactoryList( 'your_app.factories.UserPhotoFactory', # 替换为实际的UserPhotoFactory路径 size=2, factory_related_name='user' ) class UserPhotoFactory(DjangoModelFactory): class Meta: model = UserPhoto user = factory.SubFactory(UserFactory) order = factory.Faker('pyint', min_value=0, max_value=4) url = factory.Faker( 'random_element', elements=['https://picsum.photos/seed/picsum/200/300', 'https://picsum.photos/seed/pssss/200/300', 'https://picsum.photos/seed/picwum/200/300'] ) class ProfileFactory(DjangoModelFactory): class Meta: model = Profile user = factory.SubFactory(UserFactory) bio = factory.LazyAttribute(lambda o: FAKE.paragraph(nb_sentences=5, ext_word_list=['abc', 'def', 'ghi', 'jkl']))
说明
RelatedFactoryList的size=2指定每个User生成2张UserPhotofactory_related_name='user'对应UserPhoto模型中关联User的字段名- 调用
ProfileFactory.create_batch(10)时,会自动创建10个User,每个User对应1个Profile和2个UserPhoto,所有对象关联关系完全匹配
内容的提问来源于stack exchange,提问作者rafaelHTML
相关产品推荐
相关产品推荐

