这是 Xelnor 的答案,但修复了错误,以便只function_instantiation
创建一个,而不是为每个parameter
/parameter_setting
对创建一个。
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
# This overrides the function_instantiation created inside
# ParameterSettingFactory, which then overrides the Function creation,
# with the SelfAttribute('..function_instantiation.function') syntax.
parameter_setting_1 = factory.RelatedFactory(ParameterSettingFactory,
'function_instantiation')
parameter_setting_2 = factory.RelatedFactory(ParameterSettingFactory,
'function_instantiation')
下面演示了使用此模式的任何人可能会遇到的其他一些问题的解决方案,例如覆盖相关对象的值,以及到其他表的链接,这些表本身是链接的。它主要来自 Xelnor 在他的回答中介绍的技术。
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))
# I found it neater not to inherit in the end, due to needing quite a lot of
# additional complexity not included in my original question.
class FunctionToParameterSettingsFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.FunctionInstantiation
name = factory.Sequence(lambda n: "Custom instantiation name %d" % n)
# You can call Sequence to pass values to SubFactories
function = factory.SubFactory(FunctionFactory,
name=factory.Sequence(lambda n: "Custom function %d" % n))
parameter_setting_1 = factory.RelatedFactory(ParameterSettingFactory,
'function_instantiation',
# Note the __ syntax for override values for nested objects:
parameter__name='Parameter 1',
name='Parameter Setting 1')
# Possible to use Sequence here too, and makes looking at data easier
parameter_setting_2 = factory.RelatedFactory(ParameterSettingFactory,
'function_instantiation',
parameter__name=factory.Sequence(lambda n: "Param 1 for fn %d" % n),
name=factory.Sequence(lambda n: "Param Setting 1 for fn %d" % n))
我现在需要创建一个包含一些数据列的数据集,并将 parameter_setting 记录与这些列连接起来。为此,这将在末尾进行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())
# self is the `FunctioInstantiation` Django object just created by the `FunctionToParameterSettingsFactory`
for parameter_setting in self.parametersetting_set.all():
if parameter_setting.name == 'age_in':
parameter_setting.column_id = column_ids_by_name['Age']
parameter_setting.save()
elif parameter_setting.name == 'income_in':
parameter_setting.column_id = column_ids_by_name['Income']
parameter_setting.save()
诚然,这有点 hacky。我尝试传入column=column_1
RelatedFactory 调用,但这触发了多个数据集的创建,每一列都链接到不同的数据集。我用 SelfAttribute 和 LazyAttribute 尝试了各种杂技,但是你不能在 RelatedFactory 调用中使用,你不能用 SubFactory(SelfAttribute()) 创建一些东西然后将它传递给 RelatedFactory,因为这会破坏 SelfAttribute(见我的另一个问题)。
在我的真实代码中,我还有几个带有数据集外键的模型,它们都绑定得很好。