Reputation: 57541
I'm writing unit tests for a Django app which use factory_boy
test fixtures. In some cases, one fixture might try to create an object that was already created by another fixture, which leads to error messages similar to the following:
django.db.utils.IntegrityError: duplicate key value violates unique constraint "lucy_web_sessiontype_title_c207e4f8_uniq"
DETAIL: Key (title)=(Postpartum Doula Support) already exists.
To avoid this, my first inclination is to write a try..except
block, like so:
try:
SessionTypeFactory(title='Welcome')
except psycopg2.IntegrityError as e:
pass
However, it seems like it would be more elegant to use the django_get_or_create
option described at http://factoryboy.readthedocs.io/en/latest/orms.html#factory.django.DjangoOptions.django_get_or_create.
However, as far as I can tell from http://factoryboy.readthedocs.io/en/latest/reference.html#factory.FactoryOptions, options specifie in the factory's Meta
class will apply to all instances, whereas I would only like it to only apply to this instance. Is it possible to specify these options in the constructor?
Upvotes: 1
Views: 2658
Reputation: 3589
The doc is slightly misleading. What is documented in the FactoryOptions
section is the list of options available in the class Meta
part.
In your case, you could go with the following code sample:
class SessionTypeFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.SessionType
django_get_or_create = ['title']
# your fields here
This will perform a SessionType.objects.get_or_create(title=fields.pop('title'), defaults=fields)
every time you create an instance.
Since you have a unique
condition on the title
field, you can safely put that behavior in place at the SessionTypeFactory
level.
Upvotes: 3
Reputation: 57541
After perusing the source code a bit, it seems from this line in the DjangoModelFactory
class definition that this is not possible. The class contains the following class method:
class DjangoModelFactory(base.Factory):
@classmethod
def _create(cls, model_class, *args, **kwargs):
"""Create an instance of the model, and save it to the database."""
manager = cls._get_manager(model_class)
if cls._meta.django_get_or_create:
return cls._get_or_create(model_class, *args, **kwargs)
return manager.create(*args, **kwargs)
From this, it seems that django_get_or_create
is a class attribute and not an instance attribute, so it is not possible to specify django_get_or_create
per instance. Please correct me if I'm wrong!
Upvotes: 1