Why does FactoryBoy create a new object from SubFactory despite FACTORY_DJANGO_GET_OR_CREATE

StackOverflow https://stackoverflow.com/questions/17206677

質問

I have just started using factory boy with Django. It has a setting FACTORY_DJANGO_GET_OR_CREATE that means it won't create a new object if one already exists. But when I ask for an existing object with an existing SubFactory object, it creates an unused object despite this setting.

For example, in a brand 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 has brought into being a new object of class A, even though the B object with name Beetle already exists (and is not re-created). Why, and how do I stop this new A object being created?

(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 levels of hierarchy, and it's messy to supply extra redundant parameters this way - and I can't seem to get the right combination of parameters.)

Thanks!

役に立ちましたか?

解決

The above is a problem when I also have a class C that has a foreign key to B. When I created a new CFactory object like so:

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

it also creates a new unused A object.

I have found the solution to this is simple: instead, make the new CFactory object like this:

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

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

他のヒント

You could call use:

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

That way the following two invocations are equal:

BFactory()
BFactory(a__name='Reuse this model A instance')

I believe the subfactory kicks in after the get_or_create irrespectively.

Not sure of a s9lution though, it's not a use case I've come across. IMHO fixtures that 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 complicated test case, but is safer

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top