C'est la réponse de Xelnor, mais corrige le bug de sorte que seul un function_instantiation
est créé, au lieu d'une pour chaque paire 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')
Ce qui suit montre les solutions à quelques autres problèmes toute personne utilisant ce modèle rencontrera probablement, comme remplaçant les valeurs des objets liés et des liens vers d'autres tables, eux-mêmes liés. Il s'inspire largement des techniques introduites par Xelnor dans sa réponse.
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))
J'ai besoin maintenant de créer un ensemble de données avec des colonnes de données, et joindre les documents parameter_setting avec ces colonnes. Pour ce faire, cela va à la fin de 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()
C'est certes un peu hacky. J'ai essayé de passer column=column_1
dans les appels RelatedFactory, mais cela a déclenché la création de plusieurs jeux de données, chaque colonne étant liée à un autre.J'ai essayé toutes sortes d'acrobaties avec SelfAttribute et LazyAttribute, mais vous ne pouvez pas utiliser dans un appel RelatedFactory, et vous ne pouvez pas créer quelque chose avec SubFactory (SelfAttribute()), puis le passer dans RelatedFactory, car cela casse SelfAttribute (voir my other question).
Dans mon code réel j'avais plusieurs autres modèles avec une clé étrangère à l'ensemble de données et tout s'est bien passé.
Mes modifications ont été rejetées ect, désolé @Xelnor, j'ai essayé de garder la réponse crédit avec vous. – Chris
Il y a un bug dans le dernier exemple de code. 'dataset' est créé de façon répétée, de sorte que' column_1' et 'column_2' obtiennent des ensembles de données différents (tous deux avec le champ' name' surchargé). Si je crée un 'column_3' avec' dataset = factory.LazyAttribute (lambda col: col.factory_parent.dataset) ', cela fonctionne très bien. Si j'ajoute ensuite 'column_3' à un appel' ParameterSettingFactory', j'obtiens 'AttributeError: Le dataset du paramètre est inconnu. 'Et factory_boy ne trouve que les locals ParameterSettingFactory, et pas factory_parent. – Chris
J'ai résolu le problème ci-dessus, [décrit ici] (http://stackoverflow.com/posts/33110180/edit), et mis à jour la réponse. – Chris