工厂男孩随机选择一个字段选项“选择”的字段

时间:2021-11-21 02:05:05

When a field in a Django model has the option choices, see Django choices field option, it utilises an iterable containing iterables of 2 items to define which values are allowed. For example:

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

Models

楷模

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)

To generate a random value in Factory Boy for choices I would utilise factory.fuzzy.FuzzyChoice, but this only chooses an iterable of 2 items. It can not take the first item of the chosen iterable. For example:

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

Factories

工厂

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

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

Error

错误

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

Getting the first item of the tuple is not possible. For example:

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

Factories

工厂

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

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

Error

错误

TypeError: 'FuzzyChoice' object does not support indexing

It is possible with the default Python random iterator, but this generates a value on declaration time and so every factory object will have the same random value. For example:

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

Factories

工厂

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

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

How can this be solved in Factory Boy? Do I need to create a custom FuzzyAttribute? (If so, please give an example)

如何在Factory Boy中解决这个问题?我是否需要创建自定义FuzzyAttribute? (如果是,请举个例子)

4 个解决方案

#1


7  

You'll not need a FuzzyAttribute.

你不需要FuzzyAttribute。

You can either restrict the values possible and only give the int value of each product type to FuzzyChoice by doing something like this:

您可以限制可能的值,并通过执行以下操作,仅将每种产品类型的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)

It should do the work.

它应该做的工作。

Please be aware that fuzzy module has been deprecated recently, see ( https://factoryboy.readthedocs.org/en/latest/fuzzy.html), you may want to use a LazyFunction instead.

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

#2


4  

Here is how I was able to do it using factory.LazyFunction as lothiraldan suggested:

以下是我如何使用factory.LazyFunction作为lothiraldan建议:

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'

#3


0  

Because I had to do that for quite a lot of models, I came up with a more abstract version of erichonkanen's solution. I define a helper class, which I put in the top level test directory of my project and import it to the modules containing the factories:

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

test/helpers.py

测试/ 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
        )

and in app/factories.py

并在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')

#4


0  

You can do as easy as this

你可以这么简单

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

    class Meta:
        model = IceCreamProduct

PS. Don't use type as attribute

PS。不要使用type作为属性

#1


7  

You'll not need a FuzzyAttribute.

你不需要FuzzyAttribute。

You can either restrict the values possible and only give the int value of each product type to FuzzyChoice by doing something like this:

您可以限制可能的值,并通过执行以下操作,仅将每种产品类型的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)

It should do the work.

它应该做的工作。

Please be aware that fuzzy module has been deprecated recently, see ( https://factoryboy.readthedocs.org/en/latest/fuzzy.html), you may want to use a LazyFunction instead.

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

#2


4  

Here is how I was able to do it using factory.LazyFunction as lothiraldan suggested:

以下是我如何使用factory.LazyFunction作为lothiraldan建议:

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'

#3


0  

Because I had to do that for quite a lot of models, I came up with a more abstract version of erichonkanen's solution. I define a helper class, which I put in the top level test directory of my project and import it to the modules containing the factories:

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

test/helpers.py

测试/ 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
        )

and in app/factories.py

并在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')

#4


0  

You can do as easy as this

你可以这么简单

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

    class Meta:
        model = IceCreamProduct

PS. Don't use type as attribute

PS。不要使用type作为属性