Given this django model
from django.db import Model
from django.contrib.auth.models import User
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.PROTECT)
some_other_field = model.CharField(...)
I have created 2 factory for the user and the customer model:
import factory
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User
django_get_or_create = ('username',)
first_name = factory.Faker("first_name", locale="fr_FR")
last_name = factory.Faker("last_name", locale="fr_FR")
username = factory.LazyAttribute(lambda m: f"{m.first_name[0]}{m.last_name[0]}".lower())
email = factory.LazyAttribute(lambda m: f"{m.first_name.lower()}.{m.last_name.lower()}@ielo.net")
customer = factory.RelatedFactory(CustomerFactory, factory_related_name="user", user=None)
is_staff = False
class CustomerFactory(factory.django.DjangoModelFactory):
class Meta:
model = "customers.Customer"
user = factory.SubFactory('myapp.tests.fixtures.UserFactory', customer=None)
To avoid flaky tests, I have set the django_get_or_create
, since most of the time I just want a user, and I create specific classes for specific cases (UserIsStaffFactory
, UserSuperAdminFactory
)
I copied the RelatedFactory/SubFactory
from https://factoryboy.readthedocs.io/en/stable/recipes.html#example-django-s-profile but If I run:
u1 = UserFactory(username='foo')
u2 = UserFactory(username='foo')
# raise IntegrityError, UNIQUE constraint failed: customers_customer.user_i
I have solved the problem like this:
import factory
class UserFactory(factory.django.DjangoModelFactory):
first_name = factory.Faker("first_name", locale="fr_FR")
last_name = factory.Faker("last_name", locale="fr_FR")
username = factory.LazyAttribute(lambda m: f"{m.first_name[0]}{m.last_name[0]}".lower())
email = factory.LazyAttribute(lambda m: f"{m.first_name.lower()}.{m.last_name.lower()}@fakecompany.com")
customer = factory.RelatedFactory(CustomerFactory, factory_related_name="user", user=None)
is_staff = False
class Meta:
model = User
django_get_or_create = ('username',)
class CustomerFactory(factory.django.DjangoModelFactory):
class Meta:
model = "customers.Customer"
django_get_or_create = ("user",)
user = factory.SubFactory('private.tests.fixtures.UserFactory')
which seems pretty straightforward 😅