factory_boy provides custom Factory subclasses for various ORMs, adding dedicated features.
The first versions of factory_boy were designed specifically for Django, but the library has now evolved to be framework-independant.
Most features should thus feel quite familiar to Django users.
All factories for a Django Model should use the DjangoModelFactory base class.
Dedicated class for Django Model factories.
This class provides the following features:
Deprecated since version 2.4.0: See DjangoOptions.django_get_or_create.
The class Meta on a DjangoModelFactory supports an extra parameter:
New in version 2.4.0.
Fields whose name are passed in this list will be used to perform a Model.objects.get_or_create() instead of the usual Model.objects.create():
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'myapp.User' # Equivalent to ``model = myapp.models.User``
django_get_or_create = ('username',)
username = 'john'
>>> User.objects.all()
[]
>>> UserFactory() # Creates a new user
<User: john>
>>> User.objects.all()
[<User: john>]
>>> UserFactory() # Fetches the existing user
<User: john>
>>> User.objects.all() # No new user!
[<User: john>]
>>> UserFactory(username='jack') # Creates another user
<User: jack>
>>> User.objects.all()
[<User: john>, <User: jack>]
Note
If a DjangoModelFactory relates to an abstract model, be sure to declare the DjangoModelFactory as abstract:
class MyAbstractModelFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.MyAbstractModel
abstract = True
class MyConcreteModelFactory(MyAbstractModelFactory):
class Meta:
model = models.MyConcreteModel
Otherwise, factory_boy will try to get the ‘next PK’ counter from the abstract model.
Custom declarations for django.db.models.FileField
Parameters: |
|
---|
Note
If the value None was passed for the FileField field, this will disable field generation:
class MyFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.MyModel
the_file = factory.django.FileField(filename='the_file.dat')
>>> MyFactory(the_file__data=b'uhuh').the_file.read()
b'uhuh'
>>> MyFactory(the_file=None).the_file
None
Custom declarations for django.db.models.ImageField
Parameters: |
|
---|
Note
If the value None was passed for the FileField field, this will disable field generation:
Note
Just as Django’s django.db.models.ImageField requires the Python Imaging Library, this ImageField requires it too.
class MyFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.MyModel
the_image = factory.django.ImageField(color='blue')
>>> MyFactory(the_image__width=42).the_image.width
42
>>> MyFactory(the_image=None).the_image
None
Signals are often used to plug some custom code into external components code; for instance to create Profile objects on-the-fly when a new User object is saved.
This may interfere with finely tuned factories, which would create both using RelatedFactory.
To work around this problem, use the mute_signals() decorator/context manager:
Disable the list of selected signals when calling the factory, and reactivate them upon leaving.
# foo/factories.py
import factory
import factory.django
from . import models
from . import signals
@factory.django.mute_signals(signals.pre_save, signals.post_save)
class FooFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.Foo
# ...
def make_chain():
with factory.django.mute_signals(signals.pre_save, signals.post_save):
# pre_save/post_save won't be called here.
return SomeFactory(), SomeOtherFactory()
factory_boy supports Mogo-style models, through the MogoFactory class.
Mogo is a wrapper around the pymongo library for MongoDB.
factory_boy supports MongoEngine-style models, through the MongoEngineFactory class.
mongoengine is a wrapper around the pymongo library for MongoDB.
Dedicated class for MongoEngine models.
This class provides the following features:
Note
If the associated class <factory.FactoryOptions.model is a mongoengine.EmbeddedDocument, the create() function won’t “save” it, since this wouldn’t make sense.
This feature makes it possible to use SubFactory to create embedded document.
Factoy_boy also supports SQLAlchemy models through the SQLAlchemyModelFactory class.
To work, this class needs an SQLAlchemy session object affected to the Meta.sqlalchemy_session attribute.
Dedicated class for SQLAlchemy models.
This class provides the following features:
Deprecated since version 2.4.0: See sqlalchemy_session.
In addition to the usual parameters available in class Meta, a SQLAlchemyModelFactory also supports the following settings:
SQLAlchemy session to use to communicate with the database when creating an object through this SQLAlchemyModelFactory.
A (very) simple exemple:
from sqlalchemy import Column, Integer, Unicode, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
session = scoped_session(sessionmaker())
engine = create_engine('sqlite://')
session.configure(bind=engine)
Base = declarative_base()
class User(Base):
""" A SQLAlchemy simple model class who represents a user """
__tablename__ = 'UserTable'
id = Column(Integer(), primary_key=True)
name = Column(Unicode(20))
Base.metadata.create_all(engine)
class UserFactory(SQLAlchemyModelFactory):
class Meta:
model = User
sqlalchemy_session = session # the SQLAlchemy session object
id = factory.Sequence(lambda n: n)
name = factory.Sequence(lambda n: u'User %d' % n)
>>> session.query(User).all()
[]
>>> UserFactory()
<User: User 1>
>>> session.query(User).all()
[<User: User 1>]