2016-04-15 31 views
1

Wenn ein Feld in einem Django-Modell die Optionsauswahlmöglichkeiten enthält, siehe Django choices field option, verwendet es eine iterierbare Anzahl von Iterablen von 2 Elementen, um zu definieren, welche Werte zulässig sind. Zum Beispiel:Factory Boy-Zufallsauswahl für ein Feld mit Feldoption "Auswahlmöglichkeiten"

Modelle

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) 

auf einen zufälligen Wert in der Fabrik Boy für Entscheidungen generieren ich factory.fuzzy.FuzzyChoice verwenden würde, aber dies wählt nur eine iterable von 2 Artikeln. Es kann nicht das erste Element des ausgewählten iterablen Elements verwenden. Zum Beispiel:

Fabriken

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

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

Fehler

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

das erste Element des Tupels zu erhalten ist nicht möglich. Zum Beispiel:

Fabriken

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

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

Fehler

TypeError: 'FuzzyChoice' object does not support indexing 

Es ist möglich, mit dem Standard-Python zufällig Iterator, aber dies erzeugt einen Wert auf der Deklaration und so jedes Factory-Objekt wird denselben zufälligen Wert haben. Zum Beispiel:

Fabriken

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

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

Wie kann dies in der Fabrik Boy gelöst werden? Muss ich ein benutzerdefiniertes FuzzyAttribute erstellen? (Wenn ja, bitte geben Sie ein Beispiel)

Antwort

4

Sie brauchen kein FuzzyAttribute.

Sie können entweder die Werte möglich einschränken und nur den int-Wert der einzelnen Warentypen zu FuzzyChoice geben, indem so etwas wie dies zu tun:

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) 

Es sollte die Arbeit machen.

Bitte beachten Sie, dass das Fuzzy-Modul kürzlich veraltet ist, siehe (https://factoryboy.readthedocs.org/en/latest/fuzzy.html), möchten Sie stattdessen eine LazyFunction verwenden.

+0

Thank Sie! Dies löst mein Problem. Ich werde auch versuchen, alle meine unscharfen Attribute zu ersetzen, – Robin

4

Hier ist, wie ich in der Lage war, es zu tun mit factory.LazyFunction als lothiraldan vorgeschlagen:

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

Weil ich das für eine ganze Reihe von Modellen zu tun hatte, kam ich mit einer abstrakteren Version von erichonkanen-Lösung auf .Ich definiere eine Hilfsklasse, die ich in der obersten Ebene Testverzeichnis meines Projekts setzen und importieren Sie es an die Module die Fabriken enthalten:

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 
     ) 

und in 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')