19

当 Django 模型中的字段具有选项选项时,请参阅Django 选项字段选项,它利用包含 2 个项目的可迭代对象的可迭代对象来定义允许的值。例如:

楷模

class IceCreamProduct(models.Model):
    PRODUCT_TYPES = (
        (0, 'Soft Ice Cream'),
        (1, 'Hard Ice Cream'),
        (2, 'Light Ice Cream'),
        (3, 'French Ice Cream'),
        (4, 'Italian-style Gelato'),
        (5, 'Frozen Dairy Dessert'),
    )
    type = models.PositiveSmallIntegerField('Type', choices=PRODUCT_TYPES, default=0)

为了在 Factory Boy 中为选项生成随机值,我会使用 factory.fuzzy.FuzzyChoice,但这只会选择 2 个项目的可迭代项。它不能取所选迭代的第一项。例如:

工厂

class IceCreamProductFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = IceCreamProduct

    type = factory.fuzzy.FuzzyChoice(IceCreamProduct.PRODUCT_TYPES)

错误

TypeError: int() argument must be a string, a bytes-like object or a number, not 'tuple'

获取元组的第一项是不可能的。例如:

工厂

class IceCreamProductFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = IceCreamProduct

    type = factory.fuzzy.FuzzyChoice(IceCreamProduct.PRODUCT_TYPES)[0]

错误

TypeError: 'FuzzyChoice' object does not support indexing

使用默认的 Python 随机迭代器是可能的,但这会在声明时生成一个值,因此每个工厂对象都将具有相同的随机值。例如:

工厂

class IceCreamProductFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = IceCreamProduct

    type = random.choice(IceCreamProduct.PRODUCT_TYPES)][0]

工厂男孩如何解决这个问题?我需要创建自定义 FuzzyAttribute 吗?(如果有,请举个例子)

4

5 回答 5

26

您不需要 FuzzyAttribute。

您可以通过执行以下操作来限制可能的值,并且仅将每种产品类型的 int 值提供给 FuzzyChoice:

PRODUCT_IDS = [x[0] for x in IceCreamProduct.PRODUCT_TYPES]
class IceCreamProductFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = IceCreamProduct

    type = factory.fuzzy.FuzzyChoice(PRODUCT_IDS)

它应该做的工作。

请注意,模糊模块最近已被弃用,请参阅(https://factoryboy.readthedocs.org/en/latest/fuzzy.html),您可能想要使用 LazyFunction 代替。

于 2016-04-15T10:24:30.940 回答
9

这是我使用factory.LazyFunctionlothiraldan建议的方法:

import random

...


def get_license_type():
    "Return a random license type from available choices."
    lt_choices = [x[0] for x in choices.LICENSE_TYPE_CHOICES]
    return random.choice(lt_choices)


def get_line_type():
    "Return a random line type from available choices."
    lt_choices = [x[0] for x in choices.LINE_TYPE_CHOICES]
    return random.choice(lt_choices)


class ProductFactory(ModelFactory):
    name = factory.Faker('name')
    description = factory.Faker('text')
    license_type = factory.LazyFunction(get_license_type)
    line_type = factory.LazyFunction(get_line_type)

    class Meta:
        model = 'products.ProductBaseV2'
于 2016-04-23T05:51:18.140 回答
9

你可以像这样简单

class IceCreamProductFactory(factory.django.DjangoModelFactory):
    icecream_flavour = factory.Faker(
        'random_element', elements=[x[0] for x in IceCreamProduct.PRODUCT_TYPES]
    )

    class Meta:
        model = IceCreamProduct

PS。不要type用作属性,使用内置函数名称作为属性是一种不好的做法

于 2018-03-12T15:42:24.430 回答
6

因为我必须对很多模型都这样做,所以我想出了一个更抽象的 erichonkanen 解决方案版本。我定义了一个帮助类,我把它放在我项目的顶级测试目录中,并将它导入到包含工厂的模块中:

test/helpers.py

import factory
import random


class ModelFieldLazyChoice(factory.LazyFunction):
    def __init__(self, model_class, field, *args, **kwargs):
        choices = [choice[0] for choice in model_class._meta.get_field(field).choices]
        super(ModelFieldLazyChoice, self).__init__(
            function=lambda: random.choice(choices),
            *args, **kwargs
        )

并且在app/factories.py

from app.models import IceCreamProduct
from test.helpers import ModelFieldLazyChoice

class IceCreamProductFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = IceCreamProduct

    type = ModelFieldLazyChoice(IceCreamProduct, 'type')
于 2018-01-12T19:57:20.453 回答
0

如果你做出基于类的选择......

class IceCreamProduct(models.Model):
    class ProductTypes(models.TextChoices):
        soft_ice_crem = (0, 'Soft Ice Cream')
        hard_ice_cream = (1, 'Hard Ice Cream')
        ...

class IceCreamProductFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = IceCreamProduct

    type = factory.fuzzy.FuzzyChoice(IceCreamProduct.ProductTypes)
    ...
于 2021-12-21T16:01:40.560 回答