2016-04-15 52 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')