I'm looking to use FactoryBoy to ensure that a model with foreign keys to other models that indirectly share foreign keys are generated with the same instances (I realize that’s pretty hard to grok, here’s a code example):
from django.db import models
import factory
class Foo(models.Model):
name = models.CharField(max_length=32)
class Bar(models.Model):
foo = models.ForeignKey(Foo, on_delete=models.PROTECT)
class Baz(models.Model):
foo = models.ForeignKey(Foo, on_delete=models.PROTECT)
class HasBarAndBaz(models.Model):
bar = models.ForeignKey(Bar, on_delete=models.PROTECT)
baz = models.ForeignKey(Baz, on_delete=models.PROTECT)
class HasBarAndBazFactory(factory.django.DjangoModelFactory):
class Meta:
model = HasBarAndBaz
bar = factory.SubFactory(BarFactory)
baz = factory.SubFactory(BazFactory)
The desire here would be to ensure that the following occurs
has_bar_and_baz = HasBarAndBazFactory()
has_bar_and_baz.bar.foo === has_bar_and_baz.baz.foo # should be True
I can think of a couple solutions, but I’m curious to know if there’s a “FactoryBoy” way to do this, without needing to write a wrapper function that accepts a product_line kwarg and passes it.
I thought about using a RelatedFactory
, and then referencing that as the default foo
kwarg to the SubFactories, but a RelatedFactory gets generated after the base factory.
I played around with a couple solutions that broke, but so far this seems to be working - also has benefit of the foo
kwarg being optional, something that didn’t work in a few of my attempts:
class HasBarAndBazFactory(factory.django.DjangoModelFactory):
class Meta:
model = HasBarAndBaz
exclude = ('foo',)
foo = factory.SubFactory(FooFactory)
bar = factory.SubFactory( BarFactory, foo=factory.SelfAttribute('..foo'))
baz = factory.SubFactory( BazFactory, foo=factory.SelfAttribute('..foo'))
I knew about exclude, but I didn’t know that you could declare subfactory attributes that did not exist on original model - I assumed that RelatedFactory had to be used for those.