Why FactoryBoy creates a new object from SubFactory, despite FACTORY_DJANGO_GET_OR_CREATE

I just started using factory boy with Django. It has a parameter FACTORY_DJANGO_GET_OR_CREATE , which means that it will not create a new object if it already exists. But when I query an existing object with an existing SubFactory object, it creates an unused object, despite this parameter.

For example, in a completely new project, I tried:

 # models.py from django.db import models class A(models.Model): name = models.CharField(max_length=10) class B(models.Model): name = models.CharField(max_length=10) a = models.ForeignKey(A) 

and

 # factories.py import factory from . import models class AFactory(factory.DjangoModelFactory): FACTORY_FOR = models.A FACTORY_DJANGO_GET_OR_CREATE = ('name',) name = factory.Sequence(lambda n: 'A-{0}'.format(n)) class BFactory(factory.DjangoModelFactory): FACTORY_FOR = models.B FACTORY_DJANGO_GET_OR_CREATE = ('name',) name = factory.Sequence(lambda n: 'B-{0}'.format(n)) a = factory.SubFactory(AFactory) 

Now:

 from factories import * a = AFactory(name="Apple") models.A.objects.all() # one object b = BFactory(a__name="Apple", name="Beetle") models.B.objects.all() models.A.objects.all() # one A object, one B object b = BFactory(name="Beetle") models.B.objects.all() models.A.objects.all() # still one B object, but now a new, unused A object too 

Then, the final call to BFactory created a new object of class A , although an object B named Beetle already exists (and is not recreated). Why and how to stop this new object A?

(I know I can get around this by calling instead:

 b = BFactory(name="Beetle", a__name="Apple") 

but in my actual use case, I have several dependencies and hierarchy levels, and it is useless to provide additional redundant parameters this way - and I cannot get the right combination of parameters.)

Thanks!

+4
source share
3 answers

This is a problem when I also have a class C that has a foreign key for B. When I created a new CFactory object, for example:

 c = CFactory(name="Cat", b__name="Beetle") 

it also creates a new unused object A

I found the solution simply: instead, create a new CFactory object as follows:

 c = CFactory(name="Cat", b=b) 

where b is either a b object or a BFactory object.

+1
source

You can invoke the use of:

 a = SubFactory(AFactory, name='Reuse this model A instance') 

Thus, the following two calls are equal:

 BFactory() BFactory(a__name='Reuse this model A instance') 
+1
source

I believe that the subtask fires after get_or_create independently.

Not sure if this is a random case that I came across. IMHO, which depend on get_or_create, have too much potential for magic. The alternative (always create) can be a little more tedious if you have a complex test case but are safer

0
source

Source: https://habr.com/ru/post/1487213/


All Articles