Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DjangoModelFactory with a SubFactory field that does not create new entries but points to existing ones instead

Let's say I have:

class CompanyFactory(DjangoModelFactory):

    class Meta:
        model = Company

    name = factory.Faker("company")
    address = factory.Faker("address")


class InvoiceFactory(DjangoModelFactory):

    class Meta:
        model = Invoice

    company = factory.SubFactory(CompanyFactory)
    num = factory.Faker("numerify", text="#"*10)
    value_total = factory.Faker("random_number", digits=3)

When I run the InvoiceFactory.create() method a new Invoice entry is created. And because Invoice "links" (foreign key) to Company, a new Company entry is also created.


Question:

What would be the right way of rewriting this so that when calling InvoiceFactory.create() an existing company entry is picked, instead of creating a new one?

like image 221
gmagno Avatar asked Oct 20 '25 18:10

gmagno


1 Answers

You have two options:

Always pick an existing company:

class InvoiceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Invoice
    company = factory.Iterator(models.Company.objects.all())

The iterator is evaluated lazily, when the first invoice is created. However, it will always cycle through the same factories.

Create some companies, then reuse:

First, add a django_get_or_create attribute to your CompanyFactory: if the provided name already exists in the database, the existing instance will be reused:

class CompanyFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Company
        django_get_or_create = ['name']
    name = factory.Faker('company')
    address = factory.Faker('address')

Then, provide values for the name field from a constant list (here using factory.fuzzy.FuzzyChoice):

class InvoiceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Invoice
    company = factory.SubFactory(
        CompanyFactory,
        name=factory.fuzzy.FuzzyChoice(['PSF', 'Django', 'The Spanish Inquisition']),
    )

Once the 3 first companies have been created, they will be reused for all following objects.

like image 117
Xelnor Avatar answered Oct 23 '25 07:10

Xelnor



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!