alias51
alias51

Reputation: 8618

How to use factory.LazyAttribute with Faker() functions

I am using factory_boy to build some fixtures in Django.

I want to use factory.LazyAttribute to build one attribute based on the condition of another attribute.

class MyFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = MyModel

    title = 'My Title' if random() < 0.5 else None
    description = factory.LazyAttribute(
        lambda a: factory.Faker(
            'paragraph', nb_sentences=1, variable_nb_sentences=False
        ) if a.title else None)

However, this returns a string being <factory.faker.Faker object at 0x000001B10597BB20> rather than executing the correct paragraph generation.

Where am I going wrong?

Upvotes: 5

Views: 8049

Answers (2)

Antonio Ercole De Luca
Antonio Ercole De Luca

Reputation: 547

Or if you need a more specific interaction with the Faker library:

from faker import Faker as RealFaker
real_faker = RealFaker()

Inside the factory:

factory.LazyAttribute(lambda a: real_faker.email())

Upvotes: 5

Xelnor
Xelnor

Reputation: 3589

factory.Faker is a special object: when a factory instantiates an object, it will ask the factory.Faker proxy to get a random value from faker.

The simplest way to achieve what you're looking for is to use factory.Maybe:

class MyFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = MyModel

    title = factory.fuzzy.FuzzyChoice(["My Title", None])
    description = factory.Maybe('title', factory.Faker('paragraph'))

Note that, in the code you shared, the title = "My title" if random() < 0.5 else None is computed exactly once, when Python parses the file. I've used factory.fuzzy.FuzzyChoice to have that random computation performed for each object. This function also uses factory_boy's randomness management features.

Another option would be to use parameters (class Params):

class MyFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = MyModel

    class Params:
        # Items here will be available to further declarations, but won't be
        # passed to the model constructor.
        description_contents = factory.Faker('paragraph')

    title = factory.fuzzy.FuzzyChoice(["My Title", None])
    description = factory.LazyAttribute(lambda a: a.description_contents if a.title else None)

Upvotes: 9

Related Questions