This is Xelnor's answer, but it fixes the error, so that only one function_instantiation , not one for each parameter / parameter_setting pair.
class FunctionFactory(factory.django.DjangoModelFactory): class Meta: model = models.Function name = factory.Sequence(lambda n: "Function %d" % n) class FunctionParameterFactory(factory.django.DjangoModelFactory): class Meta: model = models.FunctionParameter function = factory.SubFactory(FunctionFactory) class FunctionInstantiationFactory(factory.django.DjangoModelFactory): class Meta: model = models.FunctionInstantiation function = factory.SubFactory(FunctionFactory) class ParameterSettingFactory(factory.django.DjangoModelFactory): class Meta: model = models.ParameterSetting function_instantiation = factory.SubFactory(FunctionInstantiationFactory) function_parameter = factory.SubFactory(FunctionParameterFactory, function=factory.SelfAttribute('..function_instantiation.function')) class FunctionToParameterSettingsFactory(FunctionInstantiationFactory): class Meta: model = models.FunctionInstantiation
Below are solutions to several other problems that anyone who uses this template will likely encounter, such as overriding the values ββof related objects and links to other tables that are themselves related. It relies heavily on the methods that Xelnor presented in his answer.
class FunctionFactory(factory.django.DjangoModelFactory): class Meta: model = models.Function name = factory.Sequence(lambda n: "Function %d" % n) class FunctionParameterFactory(factory.django.DjangoModelFactory): class Meta: model = models.FunctionParameter name = factory.Sequence(lambda n: "Function %d" % n) function = factory.SubFactory(FunctionFactory) class ParameterSettingFactory(factory.django.DjangoModelFactory): class Meta: model = models.ParameterSetting name = factory.Sequence(lambda n: "Function %d" % n) function_instantiation = factory.SubFactory(FunctionInstantiationFactory) function_parameter = factory.SubFactory(FunctionParameterFactory, function=factory.SelfAttribute('..function_instantiation.function')) class DatasetAnd2ColumnsFactory(factory.django.DjangoModelFactory): class Meta: model = models.Function dataset = factory.SubFactory(DatasetFactory, name=factory.Sequence(lambda n: "Custom dataset %d" % n)) column_1 = factory.SubFactory(ColumnFactory, dataset=dataset, name=factory.Sequence(lambda n: "Column 1 %d" % n)) column_2 = factory.SubFactory(ColumnFactory, dataset=dataset, name=factory.Sequence(lambda n: "Column 2 %d" % n))
Now I need to create a dataset with some data columns and connect the parameter records to these columns. For this, this happens at the end of FunctionToParameterSettingsFactory :
@factory.post_generation def post(self, create, extracted, **kwargs): if not create: return dataset = DatasetAnd2ColumnsFactory() column_ids_by_name = dict((column.name, column.id) for column in dataset.column_set.all())
This is admittedly a bit of hacks. I tried to skip column=column_1 in column=column_1 calls, but this caused the creation of multiple datasets, with each column being associated with a different one. I tried all kinds of acrobatics using SelfAttribute and LazyAttribute, but you cannot use them in a RelatedFactory call, and you cannot create something with SubFactory (SelfAttribute ()) and then pass it to the "LinkedFactory" function, as this violates SelfAttribute (see my other question ).
In my real code, I had a few more models with a foreign key for the data set, and all this was well connected.