如何在 Factory Boy 中使用 lazy_attribute 和 Faker
How to use lazy_attribute with Faker in Factory Boy
上下文:
我有一个有两个日期的模型,我想对它们都使用 factory.Faker
,但第二个日期应该总是大于第一个日期。
我试过这个:
模型摘录:
class Event(models.Model):
execution_start_date = models.DateTimeField()
execution_end_date = models.DateTimeField()
工厂:
class EventFactory(factory.DjangoModelFactory):
class Meta:
model = Event
strategy = factory.BUILD_STRATEGY
execution_start_date = factory.Faker('date_time_this_year', tzinfo=pytz.utc)
@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)
但是当我尝试使用 python shell 中的工厂时,我得到了这个:
In [3]: e = EventFactory()
In [4]: e.execution_end_date
Out[4]: <factory.faker.Faker at 0x1103f51d0>
我设法让它工作的唯一方法是这样的:
@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)
faker = factory.Faker._get_faker()
return faker.date_time_between_dates(datetime_start=self.execution_start_date,
datetime_end=now(),
tzinfo=pytz.utc)
但老实说,我认为有更好的方法。
我的依赖项是:
- Django (1.8.18)
- 工厂男孩 (2.8.1)
- Faker (0.7.17)
当lazy_attribute开始发挥作用时,您手上已经生成了对象。因此,您可以像这样使用 random 和 timedelta:
@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))
或其他生成随机日期的方法。坚持factory_boy.Faker
没有意义
编辑
在我的第一个答案之后,我设法找到了一种方法来做你想做的事,它真的 simple.You 只需要用来自 Faker 的空字典调用 generate() 方法:
@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({})
起初我试图做同样的事情,但是根据 Factory Boy's documentation 对于 Faker
包装器,参数可以是任何有效的声明 .这意味着你可以将每个 faker 的参数指定为 SelfAttribute
、LazyAttribute
等。我不知道这个功能是什么时候第一次引入的,但是 3.1 版.0(2020 年 10 月)文档首次提到它。
我相信问题的例子可以重写为:
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)
所以基本上它被扭转了,并且评估了伪造者的参数而不是 LazyAttribute
的 return 值。在我的示例中,datetime_start
现在指的是 execution_start_date
解析到的任何内容,而 datetime_end
接受一个文字字符串 'now',Faker 库将用当前日期时间替换它。
上下文:
我有一个有两个日期的模型,我想对它们都使用 factory.Faker
,但第二个日期应该总是大于第一个日期。
我试过这个:
模型摘录:
class Event(models.Model):
execution_start_date = models.DateTimeField()
execution_end_date = models.DateTimeField()
工厂:
class EventFactory(factory.DjangoModelFactory):
class Meta:
model = Event
strategy = factory.BUILD_STRATEGY
execution_start_date = factory.Faker('date_time_this_year', tzinfo=pytz.utc)
@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)
但是当我尝试使用 python shell 中的工厂时,我得到了这个:
In [3]: e = EventFactory()
In [4]: e.execution_end_date
Out[4]: <factory.faker.Faker at 0x1103f51d0>
我设法让它工作的唯一方法是这样的:
@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)
faker = factory.Faker._get_faker()
return faker.date_time_between_dates(datetime_start=self.execution_start_date,
datetime_end=now(),
tzinfo=pytz.utc)
但老实说,我认为有更好的方法。
我的依赖项是:
- Django (1.8.18)
- 工厂男孩 (2.8.1)
- Faker (0.7.17)
当lazy_attribute开始发挥作用时,您手上已经生成了对象。因此,您可以像这样使用 random 和 timedelta:
@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))
或其他生成随机日期的方法。坚持factory_boy.Faker
没有意义编辑
在我的第一个答案之后,我设法找到了一种方法来做你想做的事,它真的 simple.You 只需要用来自 Faker 的空字典调用 generate() 方法:
@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({})
起初我试图做同样的事情,但是根据 Factory Boy's documentation 对于 Faker
包装器,参数可以是任何有效的声明 .这意味着你可以将每个 faker 的参数指定为 SelfAttribute
、LazyAttribute
等。我不知道这个功能是什么时候第一次引入的,但是 3.1 版.0(2020 年 10 月)文档首次提到它。
我相信问题的例子可以重写为:
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)
所以基本上它被扭转了,并且评估了伪造者的参数而不是 LazyAttribute
的 return 值。在我的示例中,datetime_start
现在指的是 execution_start_date
解析到的任何内容,而 datetime_end
接受一个文字字符串 'now',Faker 库将用当前日期时间替换它。