【问题标题】:How to use lazy_attribute with Faker in Factory Boy如何在 Factory Boy 中将lazy_attribute 与 Faker 一起使用
【发布时间】:2017-12-17 12:37:27
【问题描述】:

上下文: 我有一个有两个日期的模型,我想对它们都使用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)

【问题讨论】:

    标签: python django django-models faker factory-boy


    【解决方案1】:

    当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 没有意义

    编辑

    在我的第一个答案之后,我设法找到了一种方法来做你想做的事,这真的很简单。你只需要使用来自 Faker 的空 dict 调用 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 和 Faker,因为这两个库的目的都是按照某些规则生成随机数据,我不明白为什么要创建自己的“faker”例程如果我已经有了一个。此外,我想指出您自己的答案包括“或其他生成随机日期的方式”,那就是 Faker。在 python 中处理日期时有很多极端情况,最好的选择是使用涵盖这些极端情况的库(如时区处理等)
    • @diegueus9 是的,我理解,幸运的是,就在几天前,我找到了一种方法来做到这一点。我用另一个解决方案编辑我的答案。
    • 对于那些想知道的人,{} 是对 github.com/FactoryBoy/factory_boy/blob/… 的额外 kwargs
    • 这些可能是 kwargs,它们将 kwargs 覆盖为 Faker,所以你总是只想要 {}
    【解决方案2】:

    起初我试图做同样的事情,但根据 Factory Boy's documentationFaker 包装器,参数可以是任何有效的声明。这意味着你可以将每个faker的参数指定为SelfAttributeLazyAttribute等。我不知道这个功能是什么时候第一次引入的,但是版本3.1.0 (2020 年 10 月)docs 第一次提到它。

    我相信问题的例子可以改写为:

    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的返回值。在我的示例中,datetime_start now 指的是 execution_start_date 解析为的任何内容,datetime_end 采用文字字符串 'now',Faker 库将替换为当前日期时间。

    【讨论】:

      猜你喜欢
      • 2018-02-16
      • 2020-04-09
      • 2020-10-24
      • 2021-08-23
      • 2021-10-04
      • 2019-03-31
      • 2020-05-03
      • 2018-02-06
      • 2020-10-26
      相关资源
      最近更新 更多