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を作成する必要がありますか? (もしそうなら、例を挙げてください)
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を使用することをお勧めします。
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'
あなたはこれと同じくらい簡単に行うことができます
class IceCreamProductFactory(factory.Django.DjangoModelFactory):
type = factory.Faker(
'random_element', elements=[x[0] for x in IceCreamProduct.PRODUCT_TYPES]
)
class Meta:
model = IceCreamProduct
PS。属性としてtype
を使用しないでください
かなり多くのモデルでそれをしなければならなかったので、エリコンカネンのソリューションのより抽象的なバージョンを思いつきました。ヘルパークラスを定義します。これをプロジェクトの最上位のテストディレクトリに配置し、ファクトリを含むモジュールにインポートします。
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')