首页 > 解决方案 > 使用与 faker 集成的 factory boy 从名称列表中进行选择

问题描述

我正在尝试使用 factory.faker 从四个公司的列表中随机选择,并将它们用作生成名称列表的流量来源。我正在使用以下代码:

    from django.db import models
    import factory
    import factory.django
    from datetime import datetime
    from django.core.validators import MinValueValidator, MaxValueValidator
    from faker import Faker
    from faker.providers import BaseProvider
    import random

    fake = Faker()

    class User(models.Model):
        name = models.CharField(max_length=64)
        address = models.CharField(max_length=128)
        phone_number = models.CharField(max_length=32)
        login_date = models.DateTimeField(default=datetime.now(), blank=True)
        session_duration = models.IntegerField(default = 0, validators=  [
                           MinValueValidator(0),
                           MaxValueValidator(5)
                           ])
        traffic_source = models.CharField(max_length=32)

    class UserFactory(factory.django.DjangoModelFactory):
        class Meta:
            model = User

        name = factory.Faker('name')
        address = factory.Faker('address')
        phone_number = factory.Faker('phone_number')
        login_date = factory.Faker('date')
        session_duration = factory.Faker('random_int')



        traffic_source = random.choice(['XYZ', 'ABC', '123', '456'])

问题是,对于所有 200 次迭代,我在 python shell 中使用以下内容:

    for _ in range(200): 
        UserFactory.create()

我为每个名字都找到了同一家公司,即所有 200 个名字都为“XYZ”。

我错过了什么吗?我想为 200 次迭代中的每一次找到一家不同的公司。任何帮助深表感谢。谢谢!

标签: django-rest-frameworkfakerfactory-boy

解决方案


这来自 Python 的解析规则。

为什么?

当你写这个:

class UserFactory(factory.django.DjangoModelFactory):
    ...
    traffic_source = random.choice(['XYZ', 'ABC', '123', '456'])

Python 将执行以下步骤:

  1. 阅读类声明体;
  2. 到达线traffic_source = random.choice(['XYZ', 'ABC', '123', '456'])
  3. 评估对 的调用random.choice,它可能会返回'ABC'
  4. 读取类主体的每一行(并评估其函数调用)后,创建类:
    UserFactory = type(
        name='UserFactory',
        bases=[factory.django.DjangoModelFactory],
        {'traffic_source': 'ABC', ...},
     )```
    
    

如您所见,在解析类声明时,调用random.choice只执行一次。

基本上,这就是所有factory.XXX声明的原因:它们产生的对象只会在从工厂构建实例时执行其特定规则。

那你该怎么办?

在这里,您应该使用:

class UserFactory(factory.django.DjangoModelFactory):
    ...
    traffic_source = factory.Faker('random_choices', elements=['XYZ', 'ABC', '123', '456'])
    alt_traffic_source = factory.fuzzy.FuzzyChoice(['XYZ', 'ABC', '123', '456'])

factory.Faker('random_choices')和之间的主要区别在于factory.fuzzy.FuzzyChoices支持factory.fuzzy.FuzzyChoices懒惰地评估生成器;如果您想从查询集中进行选择,这很有用:

  • factory.Faker('random_choices', elements=Company.objects.all())将在导入时执行数据库查询;
  • factory.fuzzy.FuzzyChoice(Company.objects.all())只会在第一次UserFactory.create()调用时查询数据库。

推荐阅读