Skip to main content
 首页 » 编程设计

python之如何使用 Django 中的 Factory Boy 将值传递给依赖模型

2024年10月17日34Leo_wl

我正在开发一个开源的 django web 应用程序,我希望使用 Factory Boy 来帮助我为一些测试设置模型,但是在阅读文档和查看示例几个小时后,我认为我需要认输在此发问。

我有一个 Customer 模型,看起来有点像这样:

class Customer(models.Model): 
 
    def save(self, *args, **kwargs): 
        if not self.full_name: 
            raise ValidationError('The full_name field is required') 
        super(Customer, self).save(*args, **kwargs) 
 
 
    user = models.OneToOneField( 
        settings.AUTH_USER_MODEL, 
        on_delete=models.SET_NULL, 
        related_name='customer', 
        null=True 
    ) 
 
    created = models.DateTimeField() 
    created_in_billing_week = models.CharField(max_length=9) 
    full_name = models.CharField(max_length=255) 
    nickname = models.CharField(max_length=30) 
    mobile = models.CharField(max_length=30, default='', blank=True) 
    gocardless_current_mandate = models.OneToOneField( 
        BillingGoCardlessMandate, 
        on_delete=models.SET_NULL, 
        related_name='in_use_for_customer', 
        null=True, 
    ) 

我还在使用来自 django.contrib.auth 的标准 Django 用户模型。

这是我的工厂代码:

class UserFactory(DjangoModelFactory): 
 
    class Meta: 
        model = get_user_model() 
 
 
class CustomerFactory(DjangoModelFactory): 
 
    class Meta: 
        model = models.Customer 
 
    full_name = fake.name() 
    nickname = factory.LazyAttribute(lambda obj: obj.full_name.split(' ')[0]) 
 
    created = factory.LazyFunction(timezone.now) 
    created_in_billing_week = factory.LazyAttribute(lambda obj: str(get_billing_week(obj.created))) 
 
    mobile = fake.phone_number() 
 
    user = factory.SubFactory(UserFactory, username=nickname, 
        email="{}@example.com".format(nickname)) 

就我而言,我希望能够产生这样的客户

CustomerFactory(fullname="Joe Bloggs") 

并使用正确的用户名和电子邮件地址生成相应的用户。

现在,我收到此错误:

  AttributeError: The parameter full_name is unknown. Evaluated attributes are {'email': '<factory.declarations.LazyAttribute object at 0x111d999e8>@example.com'}, definitions are {'email': '<factory.declarations.LazyAttribute object at 0x111d999e8>@example.com', 'username': <DeclarationWrapper for <factory.declarations.LazyAttribute object at 0x111d999e8>>}. 

我认为这是因为我依赖于客户中的惰性属性,在创建用户工厂之前不会调用它。

如果我希望能够使用工厂创建 Customer 模型实例,并如上所述具有相应的用户,我应该如何做?

完整模型的值(value)可见 here on the github repo

请您参考如下方法:

在这种情况下,最好的方法是从 the customer declarations 中选取值:

class CustomerFactory(DjangoModelFactory): 
 
    class Meta: 
        model = models.Customer 
 
    full_name = factory.Faker('name') 
    nickname = factory.LazyAttribute(lambda obj: obj.full_name.split(' ')[0]) 
 
    created = factory.LazyFunction(timezone.now) 
    created_in_billing_week = factory.LazyAttribute(lambda obj: str(get_billing_week(obj.created))) 
 
    mobile = factory.Faker('phone_number') 
 
    user = factory.SubFactory( 
        UserFactory, 
        username=factory.SelfAttribute('..nickname'), 
        email=factory.LazyAttribute(lambda u: "{}@example.com".format(u.username))) 
    ) 

此外,使用 factory.Faker('field_name') 为每个实例获取随机值:行 fullname = fake.name() 类声明 等同于:

DEFAULT_FULL_NAME = fake.name() 
 
class CustomerFactory(DjangoModelFactory): 
    full_name = DEFAULT_FULL_NAME 
 
    class Meta: 
        model = models.customer 

而 factory.Faker('name') 等同于:

class CustomerFactory(DjangoModelFactory): 
    full_name = factory.LazyFunction(fake.name) 
 
    class Meta: 
        model = models.customer 

即 fake.name() 将为使用该工厂构建的每个模型提供不同的名称。