python 带有字段选项“choices”的字段的Factory Boy随机选择

uqjltbpv  于 2023-02-15  发布在  Python
关注(0)|答案(6)|浏览(93)

当Django模型中的字段有choices选项时,请参见Django choices字段选项,它使用包含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]

如何在Factory Boy中解决这个问题?我需要创建一个自定义的FuzzyAttribute吗?(如果需要,请给予)

cig3rfwq

cig3rfwq1#

您将不需要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。

jexiocij

jexiocij2#

你可以做得这么简单

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

    class Meta:
        model = IceCreamProduct

另外,不要将type用作属性,it is a bad practice to use a built-in function name as an attribute

polhcujo

polhcujo3#

下面是我如何按照lothiraldan的建议使用factory.LazyFunction来实现的:

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'
mbyulnm0

mbyulnm04#

因为我不得不为很多模型做这些,所以我想出了一个更抽象的erichonkanen的解决方案,我定义了一个helper类,我把它放在我的项目的顶层test目录中,并把它导入到包含工厂的模块中:
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')
hkmswyz6

hkmswyz65#

如果你根据阶级来选择...

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)
    ...
k4ymrczo

k4ymrczo6#

我用这个:

from factory import LazyAttribute
from django.db.models import TextChoices

class CustomChoices(models.TextChoices):
    ONE = 'one', 'First Option'
    TWO = 'two', 'Second Option'
    OTHER = 'other'

class CustomFactory(DjangoModelFactory):
    system = LazyAttribute(lambda _: random.choice(CustomChoices.values))

相关问题