How to I pass values into dependent models with Factory Boy in Django?
<p>Im' working on an open source django web app, and I'm looking to use Factory Boy to help me setting up models for some tests, but after a few hours reading the docs and looking at examples, I think I need to accept defeat and ask here.</p>

<p>I have a Customer model which looks a bit like this:</p>

<pre><code>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,
    )
</code></pre>

<p>I am also using the standard Django User Model, from django.contrib.auth.</p>

<p>Here's my factory code:</p>

<pre><code>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))
</code></pre>

<p>In my case, I want to be able to generate a customer like so</p>

<pre><code>CustomerFactory(fullname="Joe Bloggs")
</code></pre>

<p>And have the corresponding user generated, with the correct username, and email address.</p>

<p>Right now, I'm getting this error:</p>

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

<p>I think this is because I'm relying on a lazy attribute here in the customer, which isn't called before the user factory is created.</p>

<p>How <em>should</em> I be doing this if I want to be able to use a factory to create the Customer model instance, with a corresponding user as described above?</p>

<p>For what it's worth the full model is visible <a href="https://github.com/productscience/blue-world-lite/blob/master/join/models.py#L226" rel="nofollow">here on the github repo</a></p>

<p>In that case, the best way is to pick values from <a href="http://factoryboy.readthedocs.io/en/latest/reference.html#parents" rel="nofollow">the customer declarations</a>:</p>

<pre><code>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)))
    )
</code></pre>

<p>Also, use <code>factory.Faker('field_name')</code> to get random values for each instance: the line <code>fullname = fake.name()</code> <strong>in the class declaration</strong> is equivalent to:</p>

<pre><code>DEFAULT_FULL_NAME = fake.name()

class CustomerFactory(DjangoModelFactory):
    full_name = DEFAULT_FULL_NAME

    class Meta:
        model = models.customer
</code></pre>

<p>Whereas <code>factory.Faker('name')</code> is equivalent to:</p>

<pre><code>class CustomerFactory(DjangoModelFactory):
    full_name = factory.LazyFunction(fake.name)

    class Meta:
        model = models.customer
</code></pre>

<p>i.e <code>fake.name()</code> will provide a different name to each model built with this factory.</p>

python django factory-boy