在factory_boy中获取关联的子记录的ID [英] Getting id of associated child records in factory_boy

查看:418
本文介绍了在factory_boy中获取关联的子记录的ID的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数,一些参数,然后是一个专门的实例化,每个函数的参数都有一些设置。所以我有一个如下结构:

I have a function with a number of parameters, then a specialized instantiation of that function, with some settings for each of the function's parameters. So I have a structure like the following:

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 创建参数

但在 FunctionInstantiationFactory 中,我不能使用 factory.RelatedFactory(ParameterSetting) code>创建 ParameterSettings ,因为我无法访问参数 FunctionFactory ,所以我无法设置 parameter_setting.function_parameter_id

But in FunctionInstantiationFactory I can't use factory.RelatedFactory(ParameterSetting) to create ParameterSettings, because I don't have access to the parameter objects created within FunctionFactory, so I can't set parameter_setting.function_parameter_id.

如何 FunctionInstantiationFactory 查找 FunctionFactory parameter_id C>?可以从 RelatedFactory(FunctionFactory)的返回值获取它们吗?或者我需要查看数据库?

How can FunctionInstantiationFactory look up the parameter_id of parameters created in FunctionFactory? Can I get at them from the return value of RelatedFactory(FunctionFactory)? Or do I need to look at the database?

推荐答案

这是Xelnor的答案,但修复了错误,以便只有一个 function_instantiation 被创建,而不是每个参数 / parameter_setting pair 。

This is Xelnor's answer, but fixes the bug so that only one function_instantiation is created, rather than 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

    # 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在他的答案中介绍的技术。

The following demonstrates the solutions to a few other problems anyone using this pattern will probably encounter, such as overriding related objects' values, and links to other tables, themselves linked. It draws largely from techniques Xelnor introduced 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))


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

我现在需要使用一些数据列创建数据集,并使用这些列连接参数_setting记录。为了做到这一点,这在$ code> FunctionToParameterSettingsFactory 的结尾处:

I now need to create a dataset with some columns of data, and join the parameter_setting records with those columns. To do so, this goes 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())

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

这是不可否认的有点黑客。我尝试在RelatedFactory调用中传递 column = column_1 ,但是触发了多个数据集的创建,每个列都链接到不同的数据集。我使用SelfAttribute和LazyAttribute尝试了各种各样的杂技,但是您不能在RelatedFactory调用中使用,并且您无法使用SubFactory(SelfAttribute())创建某些内容,然后将其传递到RelatedFactory中,因为它会破坏SelfAttribute(请参阅我的其他问题)。

This is admittedly a bit hacky. I tried passing column=column_1 in the RelatedFactory calls, but that triggered creation of multiple datasets, each column linked to a different one. I tried all sorts of acrobatics with SelfAttribute and LazyAttribute, but you can't use either in a RelatedFactory call, and you can't create something with SubFactory(SelfAttribute()) and then pass it into RelatedFactory, as that breaks SelfAttribute (see my other question).

在我的实际代码中,我还有几个具有数据集外键的模型,并将其全部捆绑起来。

In my real code I had several more models with a foreign key to dataset and it all tied up fine.

这篇关于在factory_boy中获取关联的子记录的ID的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆