question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

FactoryBoy creates a new object from SubFactory despite FACTORY_DJANGO_GET_OR_CREATE

See original GitHub issue

I am using the setting FACTORY_DJANGO_GET_OR_CREATE. But in some cases, 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 typed:

# 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)

Then:

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

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!

(I also asked this on StackOverflow here too.)

Issue Analytics

  • State:open
  • Created 10 years ago
  • Reactions:4
  • Comments:11 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
nicolasromacommented, Apr 6, 2021

Hi @rbarrois! I was working and suddenly I run into this issue. I’m glad that you already know whats going on. I leave here for you 2 questions.

  1. Why this error seems to be not idempotent? Debugging the issue I found out that I call the Factory with the same args and some tomes returns the one already created, other times creates a new one and other times it returns an Exception
  2. Is there any way to solve this temporally until is fixed?

Thanks in advanced Regards

0reactions
dailloufcommented, Oct 18, 2022

Hello everyone,

I’ve just looked at how subfactories are called, and it appeared that any kwargs in the SubFactory call are passed to the factory (the first argument in that call)

So I tried with the following and it works just fine

class BatchFileFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = BatchFile
        django_get_or_create = ('id',)


class RefundFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Refund

    batch_file = factory.SubFactory(BatchFileFactory, id=122)
    amount = 50

And then several calls to RefundFactory all use the same BatchFile with id 122.

Seems like factory-boy also accepts factory.SelfAttribute calls inside those kwargs, like so,

class BatchFileFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = BatchFile
        django_get_or_create = ('id',)


class RefundFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Refund

    batch_file = factory.SubFactory(BatchFileFactory, id=factory.SelfAttribute("..amount"))
    amount = 50

But then “…amount” must be a field on the upper object’s class, here Refund.

Hope this can help

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why does FactoryBoy create a new object from SubFactory ...
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...
Read more >
Common recipes — Factory Boy stable documentation
When a related object should be created upon object creation (e.g a reverse ForeignKey from another Model ), use a RelatedFactory declaration:.
Read more >
Can You Create A Factoryboy Subfactory That Only Creates ...
Why does FactoryBoy create a new SubFactory object despite FACTORYDJANGOGETORCREATE I have just started using factory boy with Django.
Read more >
Model Your Models With Factory Boy (Setting Up Chained ...
As a factory is creating a new object, when it reaches an attribute which calls SubFactory with another model's factory, it will go...
Read more >
Abusing Factory Boy sequences in Django unittests | JoeQuery
If we were to create a BookmarkFactory instance in a test, factory boy would automatically create a User and Article object for the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found