9👍
When lazy_attribute come into play you already have generated object on your hand. So you can work with, for example, random and timedelta, like this:
@factory.lazy_attribute
def execution_end_date(self):
max_days = (now() - self.execution_start_date).days
return self.execution_start_date + timedelta(random.randint(1, max_days))
or some other way to generate random date. There is no point to stick to factory_boy.Faker
EDIT
After my first answer I manage to found a way to do what you want, it’s really simple.You just need to call generate() method with empty dict from Faker:
@factory.lazy_attribute
def execution_end_date(self):
return factory.Faker('date_time_between_dates',
datetime_start=self.execution_start_date,
datetime_end=now(),
tzinfo=pytz.utc).generate({})
1👍
At first I was trying to do the same thing, but according to Factory Boy’s documentation for the Faker
wrapper, the parameters can be any valid declaration. That means that you’re allowed to specify each of the faker’s parameter as a SelfAttribute
, LazyAttribute
, etc. I don’t know when this feature was first introduced, but version 3.1.0 (Oct 2020) docs mentions it for the first time.
I believe that the question’s example can be rewritten as:
class EventFactory(factory.DjangoModelFactory):
class Meta:
model = Event
strategy = factory.BUILD_STRATEGY
execution_start_date = factory.Faker('date_time_this_year', tzinfo=pytz.utc)
execution_end_date = factory.Faker('date_time_between_dates',
datetime_start=factory.SelfAttribute('..execution_start_date'),
datetime_end='now',
tzinfo=pytz.utc)
So basically it’s turned around and the faker’s parameters are evaluated instead of the LazyAttribute
‘s return value. In my example datetime_start
now refers to whatever execution_start_date
resolves to and datetime_end
takes a literal string ‘now’, that the Faker library will replace with the current datetime.