使用工厂男孩时如何覆盖模型保存功能?
How to overriding model save function when using factory boy?
我正在使用 Factory Boy 测试 Django 项目,但在测试模型时我 运行 遇到了一个问题,我已经覆盖了保存方法。
型号:
class Profile(models.Model):
active = models.BooleanField()
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE,
related_name='profiles')
department = models.ForeignKey(Department, null=True, blank=True)
category_at_start = models.ForeignKey(Category)
role = models.ForeignKey(Role)
series = models.ForeignKey(Series, null=True, blank=True)
status = models.ForeignKey('Status', Status)
def save(self, *args, **kwargs):
super(Profile, self).save(*args, **kwargs)
active_roles = []
active_status = []
for profile in Profile.objects.filter(user=self.user):
if profile.active:
active_roles.append(profile.role.code)
active_status.append(profile.status.name)
self.user.current_role = '/'.join(set(active_roles))
if 'Training' in active_status:
self.user.current_status = 'Training'
elif 'Certified' in active_status:
self.user.current_status = 'Certified'
else:
self.user.current_status = '/'.join(set(active_status))
self.user.save()
super(Profile, self).save(*args, **kwargs) ### <-- seems to be the issue.
工厂:
class ProfileFactory(f.django.DjangoModelFactory):
class Meta:
model = models.Profile
active = f.Faker('boolean')
user = f.SubFactory(UserFactory)
department = f.SubFactory(DepartmentFactory)
category_at_start = f.SubFactory(CategoryFactory)
role = f.SubFactory(RoleFactory)
series = f.SubFactory(SeriesFactory)
status = f.SubFactory(StatusFactory)
测试:
class ProfileTest(TestCase):
def test_profile_creation(self):
o = factories.ProfileFactory()
self.assertTrue(isinstance(o, models.Profile))
当我 运行 测试时,出现以下错误:
django.db.utils.IntegrityError: UNIQUE constraint failed: simtrack_profile.id
如果我在配置文件保存方法中注释掉最后一个 last/second 'super' 语句,则测试通过。我想知道这条语句是否试图用相同的 ID 再次创建配置文件?我尝试了各种方法,例如在 Meta class django_get_or_create 中指定,以及通过断开和连接 post 生成保存来覆盖工厂的 _generation 方法的各种黑客版本,但我可以让它工作。
同时,我已经设置了构建策略,但显然这不会测试我的保存方法。
非常感谢任何帮助。
J.
factory_boy
使用 Django 的 ORM 中的 MyModel.objects.create()
函数。
那个函数调用obj.save(force_insert=True)
:https://github.com/django/django/blob/master/django/db/models/query.py#L384
使用重载的 save()
函数,这意味着您得到:
- 致电
super(Profile, self).save(force_insert=True)
- [SQL:
INSERT INTO simtrack_profile SET ...;
]
- =>
self.pk
设置为新插入行的pk
- 执行您的自定义代码
- 致电
super(Profile, self).save(force_insert=True)
- 这会生成此 SQL:
INSERT INTO simtrack_profile SET id=N, ...
,其中 N
是对象的 pk
- 很明显,发生了崩溃:已经有一行
id=N
.
您应该修复 save()
函数,以便您第二次调用 super(Profile, self).save()
时不会 再次重复 *args, **kwargs
。
备注:
- 当您通过 Django 的管理添加对象时,或者您使用
Profile.objects.create()
. 时,您的代码将会中断
- 由于您没有在重载的
save()
函数中修改 self
,因此您应该能够完全删除对 super(Profile, self).save()
的第二次调用;如果您以后需要添加更多自定义行为,保留它可能有助于避免出现奇怪的错误。
我正在使用 Factory Boy 测试 Django 项目,但在测试模型时我 运行 遇到了一个问题,我已经覆盖了保存方法。
型号:
class Profile(models.Model):
active = models.BooleanField()
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE,
related_name='profiles')
department = models.ForeignKey(Department, null=True, blank=True)
category_at_start = models.ForeignKey(Category)
role = models.ForeignKey(Role)
series = models.ForeignKey(Series, null=True, blank=True)
status = models.ForeignKey('Status', Status)
def save(self, *args, **kwargs):
super(Profile, self).save(*args, **kwargs)
active_roles = []
active_status = []
for profile in Profile.objects.filter(user=self.user):
if profile.active:
active_roles.append(profile.role.code)
active_status.append(profile.status.name)
self.user.current_role = '/'.join(set(active_roles))
if 'Training' in active_status:
self.user.current_status = 'Training'
elif 'Certified' in active_status:
self.user.current_status = 'Certified'
else:
self.user.current_status = '/'.join(set(active_status))
self.user.save()
super(Profile, self).save(*args, **kwargs) ### <-- seems to be the issue.
工厂:
class ProfileFactory(f.django.DjangoModelFactory):
class Meta:
model = models.Profile
active = f.Faker('boolean')
user = f.SubFactory(UserFactory)
department = f.SubFactory(DepartmentFactory)
category_at_start = f.SubFactory(CategoryFactory)
role = f.SubFactory(RoleFactory)
series = f.SubFactory(SeriesFactory)
status = f.SubFactory(StatusFactory)
测试:
class ProfileTest(TestCase):
def test_profile_creation(self):
o = factories.ProfileFactory()
self.assertTrue(isinstance(o, models.Profile))
当我 运行 测试时,出现以下错误:
django.db.utils.IntegrityError: UNIQUE constraint failed: simtrack_profile.id
如果我在配置文件保存方法中注释掉最后一个 last/second 'super' 语句,则测试通过。我想知道这条语句是否试图用相同的 ID 再次创建配置文件?我尝试了各种方法,例如在 Meta class django_get_or_create 中指定,以及通过断开和连接 post 生成保存来覆盖工厂的 _generation 方法的各种黑客版本,但我可以让它工作。
同时,我已经设置了构建策略,但显然这不会测试我的保存方法。
非常感谢任何帮助。
J.
factory_boy
使用 Django 的 ORM 中的 MyModel.objects.create()
函数。
那个函数调用obj.save(force_insert=True)
:https://github.com/django/django/blob/master/django/db/models/query.py#L384
使用重载的 save()
函数,这意味着您得到:
- 致电
super(Profile, self).save(force_insert=True)
- [SQL:
INSERT INTO simtrack_profile SET ...;
] - =>
self.pk
设置为新插入行的pk
- [SQL:
- 执行您的自定义代码
- 致电
super(Profile, self).save(force_insert=True)
- 这会生成此 SQL:
INSERT INTO simtrack_profile SET id=N, ...
,其中N
是对象的 pk - 很明显,发生了崩溃:已经有一行
id=N
.
- 这会生成此 SQL:
您应该修复 save()
函数,以便您第二次调用 super(Profile, self).save()
时不会 再次重复 *args, **kwargs
。
备注:
- 当您通过 Django 的管理添加对象时,或者您使用
Profile.objects.create()
. 时,您的代码将会中断
- 由于您没有在重载的
save()
函数中修改self
,因此您应该能够完全删除对super(Profile, self).save()
的第二次调用;如果您以后需要添加更多自定义行为,保留它可能有助于避免出现奇怪的错误。