2016-09-17 63 views
1

Im'在开源django网络应用程序上工作,我正在使用Factory Boy来帮助我设置一些测试模型,但是在几个小时阅读文档并查看示例之后,我认为我需要接受失败并在这里问问。如何使用Django中的Factory Boy将值传递给依赖模型?

我有一个客户模型,它看起来有点像这样:

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用户模型,从django.contrib.auth。

这里是我的工厂代码:

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>>}. 

我想这是因为我依靠lazy属性在这里的客户,创建用户出厂前这不叫。

如何应该我这样做,如果我想能够使用工厂创建客户模型实例,与上述相应的用户?

对于什么是值得的完整模型可见here on the github repo

回答

1

在这种情况下,最好的办法是从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()将提供一个不同的名称来使用此工厂每个构建的模型。

+0

甜!非常感谢 - 这就是我一直在努力的! –

+0

为简洁起见,在用户子类别声明'username = factory.SelfAttribute('.. nickname')中使用['SelfAttribute'](http://factoryboy.readthedocs.io/en/latest/reference.html#parents)似乎是直接问题的解决方案。 [Factory Boy通过'SelfAttribute'将字段复制到子集的配方](http://factoryboy.readthedocs.io/en/latest/recipes.html?highlight=SelfAttribute#copying-fields-to-a-subfactory) –

相关问题