Search code examples
djangofakerfactory-boy

Django Factory Boy loop return same value


I'm trying to generate fake objets from loop but always returns the same objet

utilities.py:

...
for _ in range(number_objects):
    try:
        element = app_factories.UserFactory()
        print(element)
    except Exception as e:
        print(e)
        print(type(e))
...

factories.py

from faker import Faker
from factory.fuzzy import FuzzyChoice
from factory.django import DjangoModelFactory

fake = Faker(['es-ES'])

class UserFactory(DjangoModelFactory):
  name = fake.name()
  email = '{}@mailcom'.format(slugify(name))
  height = fake.numerify(text='1##')
  friend = FuzzyChoice(app_models.User.objects.all())

  class Meta:
    model = app_models.User

Probably it will be from the seed or generator but I don't know how to solve it. Anybody could help me please ? Thanks in advance.


Solution

  • The problem is that calls to faker are evaluated at module import time.

    What you've written is equivalent to:

    fake = Faker(['es-ES'])
    name = fake.name()  # "John Doe"
    email = '{}@mailcom'.format(slugify(name))  # 'johndoe@mailcom'
    height = fake.numerify(text='1##')  # 123
    friend = FuzzyChoice(app_models.User.objects.all())  # Lazy
    
    class UserFactory(DjangoModelFactory):
      ...
      name = "John Doe"
      email = 'johndoe@mailcom'
      height = 123
      friend = FuzzyChoice(app_models.User.objects.all())
    

    Instead, use:

    class UserFactory(DjangoModelFactory):
      ...
      name = factory.Faker("name")
      email = factory.LazyAttribute(lambda o: '{}@mailcom'.format(slugify(o.name)))
    

    You'll find a more detailed explanation of the difference between your code and using FactoryBoy's helpers in my answer there: Django Tests - User Factory with create_batch