使用与 faker 集成的 factory boy 从名字列表中选择
Choosing from a list of names using factory boy integrated with faker
我正在尝试使用 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()
我为每个名字找到了同一家公司,即 'XYZ' 为所有 200 个名字。
我错过了什么吗?我想为 200 次迭代中的每一次迭代找一家不同的公司。任何帮助深表感谢。谢谢!
这来自Python的解析规则。
为什么?
当你这样写的时候:
class UserFactory(factory.django.DjangoModelFactory):
...
traffic_source = random.choice(['XYZ', 'ABC', '123', '456'])
Python 将执行以下步骤:
- 阅读class声明体;
- 到达第
traffic_source = random.choice(['XYZ', 'ABC', '123', '456'])
行;
- 评估对
random.choice
的调用,这可能 return 'ABC'
;
- 读取 class 正文的每一行(及其函数调用已评估)后,创建 class:
UserFactory = type(
name='UserFactory',
bases=[factory.django.DjangoModelFactory],
{'traffic_source': 'ABC', ...},
)```
如您所见,在解析 class 声明时,对 random.choice
的调用仅执行 一次 。
基本上,这就是所有 factory.XXX
声明的原因:它们产生一个对象,该对象仅在从工厂构建实例时执行其特定规则。
那么,你应该怎么做?
在这里,你应该使用:
- 或者
factory.Faker
使用 Faker's random_choices
provider;
- 或
factory.fuzzy.FuzzyChoice
:
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()
时查询数据库。
虽然不是真正随机的,但您在从一组预先存在的记录中进行选择时寻找的效果也可以通过使用 FactoryBoy 的 Iterator
来实现,它也可以与 QuerySet 一起使用。例如,在这里我希望每个对象都由不同于现有假用户集的人创建:
from django.contrib.auth import get_user_model
...
# Then, within a factory class, for one of the fields:
created_by = factory.Iterator(get_user_model().objects.all())
我正在尝试使用 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()
我为每个名字找到了同一家公司,即 'XYZ' 为所有 200 个名字。
我错过了什么吗?我想为 200 次迭代中的每一次迭代找一家不同的公司。任何帮助深表感谢。谢谢!
这来自Python的解析规则。
为什么?
当你这样写的时候:
class UserFactory(factory.django.DjangoModelFactory):
...
traffic_source = random.choice(['XYZ', 'ABC', '123', '456'])
Python 将执行以下步骤:
- 阅读class声明体;
- 到达第
traffic_source = random.choice(['XYZ', 'ABC', '123', '456'])
行; - 评估对
random.choice
的调用,这可能 return'ABC'
; - 读取 class 正文的每一行(及其函数调用已评估)后,创建 class:
UserFactory = type( name='UserFactory', bases=[factory.django.DjangoModelFactory], {'traffic_source': 'ABC', ...}, )```
如您所见,在解析 class 声明时,对 random.choice
的调用仅执行 一次 。
基本上,这就是所有 factory.XXX
声明的原因:它们产生一个对象,该对象仅在从工厂构建实例时执行其特定规则。
那么,你应该怎么做?
在这里,你应该使用:
- 或者
factory.Faker
使用 Faker'srandom_choices
provider; - 或
factory.fuzzy.FuzzyChoice
:
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()
时查询数据库。
虽然不是真正随机的,但您在从一组预先存在的记录中进行选择时寻找的效果也可以通过使用 FactoryBoy 的 Iterator
来实现,它也可以与 QuerySet 一起使用。例如,在这里我希望每个对象都由不同于现有假用户集的人创建:
from django.contrib.auth import get_user_model
...
# Then, within a factory class, for one of the fields:
created_by = factory.Iterator(get_user_model().objects.all())