python – 如何在使用工厂男孩时覆盖模型保存功能?
作者:互联网
我正在使用Factory Boy来测试Django项目,并且在测试我已经覆盖了save方法的模型时遇到了一个问题.
该模型:
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
如果我在Profile保存方法中注释掉最后一个/第二个’super’语句,则测试通过.我想知道这句话是否试图使用相同的ID再次创建配置文件?我已经尝试了各种各样的东西,比如在Meta类中指定django_get_or_create和各种黑客版本的覆盖工厂的_generation方法,断开并连接后代保存,但我无法让它工作.
与此同时,我已经制定了构建策略,但显然不会测试我的save方法.
任何帮助非常感谢.
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()的第二次调用;虽然如果您需要稍后添加更多自定义行为,保留它可能有助于避免奇怪的错误.
标签:python,django,testing,factory-boy 来源: https://codeday.me/bug/20190522/1153802.html