Fields depending on one another
HI,
I'm upgrading an old project which has factories with fields depending on one another (if the first one is set, the second one takes its value from it and the other way around). It was done by overwriting the _prepare method (which has been remove in 2.9.0).
Is there a proper way to do that with declarations? I overwrote _create instead but it wouldn't work for building (and is not very clean).
The current implementation is done that way:
@classmethod
def _create(cls, model_class, *args, **kwargs):
""" Fields depending on one another """
if 'initiator' in kwargs and 'agency' not in kwargs:
kwargs['agency'] = kwargs['initiator'].agency
elif 'initiator' not in kwargs and 'agency' in kwargs:
kwargs['initiator'] = JobUserFactory(agency=kwargs['agency'])
elif 'initiator' not in kwargs and 'agency' not in kwargs:
kwargs['initiator'] = JobUserFactory()
kwargs['agency'] = kwargs['initiator'].agency
return super(MyFactory, cls)._create(model_class, *args, **kwargs)
I also tried creating my own declaration (a lazy_attribute with the parameters passed to the factory), but the parameters are not passed all the way to it.
Thanks
Would _adjust_kwargs suit your use case?
It doesn't work for every case. For example, with SelfAttribute:
class InfrastructureInterventionFactory(factory.DjangoModelFactory):
class Meta:
model = models.InfrastructureIntervention
rootequipment = factory.SubFactory(InfrastructureToolFactory, agency=factory.SelfAttribute('..agency'))
@classmethod
def _adjust_kwargs(cls, **kwargs):
if 'initiator' in kwargs and 'agency' not in kwargs:
kwargs['agency'] = kwargs['initiator'].agency
elif 'initiator' not in kwargs and 'agency' in kwargs:
kwargs['initiator'] = UserFactory(agency=kwargs['agency'])
elif 'initiator' not in kwargs and 'agency' not in kwargs:
kwargs['initiator'] = UserFactory()
kwargs['agency'] = kwargs['initiator'].agency
return kwargs
# Called without parameters
InfrastructureInterventionFactory()
# Raises
AttributeError: The parameter 'agency' is unknown.
Would something along these lines work for you?
class InfrastructureInterventionFactory(factory.DjangoModelFactory):
class Meta:
model = models.InfrastructureIntervention
agency = factory.SubFactory(AgencyFactory)
initiator = factory.SubFactory(UserFactory, agency=factory.SelfAttribute('..agency'))
rootequipment = factory.SubFactory(InfrastructureToolFactory, agency=factory.SelfAttribute('..agency'))
@classmethod
def _adjust_kwargs(cls, **kwargs):
if 'initiator' in kwargs and 'agency' not in kwargs:
kwargs['agency'] = kwargs['initiator'].agency
return kwargs
I think it might do it but I won't be able to try it before late next month.
So I actually get kwargs for all attributes, even the one not passed as parameters:
InfrastructureInterventionFactory()
# kwargs = {
# 'agency': <Agency: AGENCY 0>,
# 'initiator': <JobUser: Tom 0 Blob 0>,
# 'rootequipment': <InfrastructureTool: A0-MOUT-0000 - Tool é 0>
# }
bump
I have a similar issue that might be a pretty common use case:
With SQLAlchemy models, I want the client code to be able to pass either an id for the DB column, or an object for the corresponding relationship, and I cannot figure out a way of making it work, see:
[EDIT: I was trying to make a minimal example but I'm having trouble setting it up on the fly, I'll make one and come back]