2016-04-15 50 views
1

当Django模型中的字段具有选项选项时,请参阅Django choices field option,它利用包含2个项目的可迭代项的迭代来定义允许哪些值。例如:Factory Boy随机选择字段选项“选项”

模型

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

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

+0

谢谢您!这解决了我的问题。我还会尝试替换我所有的模糊属性, – Robin

4

这里是我如何能够使用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' 
0

因为我不得不这样做,对于相当多的车型,我想出了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')