我有一个function
,其数量为parameters
,然后是该函数的专用instantiation
,每个函数的参数都有一些settings
。所以我有如下结构:
class Function(models.Model):
name = models.CharField()
class FunctionParameter(models.Model):
function = models.ForeignKey(Function)
class FunctionInstantiation(models.Model):
function = models.ForeignKey(Function)
class ParameterSetting(models.Model):
function_instantiation = models.ForeignKey(FunctionInstantiation)
function_parameter = models.ForeignKey(FunctionParameter)
在FunctionFactory
我可以使用factory.RelatedFactory
创建parameters
。
但在FunctionInstantiationFactory
我无法使用factory.RelatedFactory(ParameterSetting)
创建ParameterSettings
,因为我无法访问parameter
内创建的FunctionFactory
个对象,所以我无法设置parameter_setting.function_parameter_id
。
FunctionInstantiationFactory
如何查找parameter_id
中创建的FunctionFactory
个参数?我可以从RelatedFactory(FunctionFactory)
的返回值获得它们吗?或者我需要查看数据库吗?
答案 0 :(得分:2)
factory.SubFactory
旨在关注 ForeignKey
;如果您想以相反的方式使用它,则应使用RelatedFactory
代替。
就你的例子而言,我会选择以下工厂:
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
exclude = ['function']
# We'll need a FunctionFactory; this field is part of 'exclude',
# thus available while building the factory but not passed to the
# target Django model
function = factory.SubFactory(FunctionFactory)
# Use the function from our Factory for both
# function_instantiation and function_parameter
function_instantiation = factory.SubFactory(FunctionInstantiationFactory,
function=factory.SelfAttribute('..function'))
function_parameter = factory.SubFactory(FunctionParameterFactory,
function=factory.SelfAttribute('..function'))
您可以添加额外的工厂FunctionWithParametersFactory
,以创建参数:
class FunctionWithParametersFactory(FunctionFactory):
parameter1 = factory.RelatedFactory(ParameterSettingFactory, 'function')
parameter2 = factory.RelatedFactory(ParameterSettingFactory, 'function')
调用该工厂将执行以下操作:
答案 1 :(得分:-1)
这是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')
。
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))
以下演示了使用此模式的任何人可能遇到的其他一些问题的解决方案,例如覆盖相关对象的值,以及链接到其他表本身的链接。它主要来自Xelnor在答案中介绍的技术。
FunctionToParameterSettingsFactory
我现在需要创建一个包含一些数据列的数据集,并将parameter_setting记录与这些列连接起来。为此,这将在@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()
:
column=column_1
这无疑是有点hacky。我尝试在RelatedFactory调用中传递CodeToTest
,但这触发了多个数据集的创建,每个列链接到不同的数据集。我尝试过使用SelfAttribute和LazyAttribute的各种杂技,但是你不能在RelatedFactory调用中使用它们,也不能用SubFactory(SelfAttribute())创建一些东西,然后将它传递给RelatedFactory,因为它会破坏SelfAttribute(参见my other question)。
在我的真实代码中,我有几个带有数据集外键的模型,它们都很好。