Skip to content

Instantly share code, notes, and snippets.

Last active October 27, 2020 15:12
Show Gist options
  • Save tobiasmcnulty/6232216 to your computer and use it in GitHub Desktop.
Save tobiasmcnulty/6232216 to your computer and use it in GitHub Desktop.
Django management command to generate factory-boy boilerplate factory definitions for all the models in a given app. The code is not intended to be usable right off the bat, it just provides a few sane defaults based on the structure of your models.
from import BaseCommand, CommandError
from django.db.models import get_models, get_app, fields
from django.db.models.fields import related
class Command(BaseCommand):
help = """Generate factory-boy factories for the given app"""
def handle(self, *args, **options):
assert len(args) == 1, 'Must specify app name as first and only argument'
app = get_app(args[0])
models = get_models(app)
app_label = models[0]._meta.app_label
print """
import factory
import datetime
import {models} as {app_label}_models
# import other requried factories here
""".format(models=app.__name__, app_label=app_label)
needed_factories = set()
created_factories = set()
for model in models:
print """
class {model_name}Factory(factory.django.DjangoModelFactory):
FACTORY_FOR = {app_label}_models.{model_name}
""".format(app_label=app_label, model_name=model.__name__)
for field in model._meta.fields:
# skip fields with default values or that can be blank
if isinstance(field, fields.AutoField):
if field.default != fields.NOT_PROVIDED:
print ' # skipped field {0} ({1}) with default value ({2})'.format(, field.__class__.__name__, field.default)
if field.blank or field.null:
print ' # skipped blank or nullable field {0} ({1})'.format(, field.__class__.__name__)
args = []
model_slug = model._meta.verbose_name.replace(' ', '-')
if field.choices:
cls = 'factory.fuzzy.FuzzyChoice'
args.append('** need choices **')
elif isinstance(field, fields.IntegerField):
cls = 'factory.fuzzy.FuzzyInteger'
elif isinstance(field, fields.EmailField):
cls = 'factory.Sequence'
args.append('lambda n: "{0}-{1}-{{}}".format(n)'.format(model_slug,
elif isinstance(field, fields.CharField) or isinstance(field, fields.TextField):
cls = 'factory.Sequence'
args.append('lambda n: "{0}-{1}-{{}}".format(n)'.format(model_slug,
elif isinstance(field, fields.DateTimeField):
cls = 'factory.fuzzy.FuzzyNaiveDateTime'
args.append(' - datetime.timedelta(days=365)')
elif isinstance(field, fields.DateField):
cls = 'factory.fuzzy.FuzzyDate'
args.append(' - datetime.timedelta(days=365)')
elif isinstance(field, related.ForeignKey) or isinstance(field, related.OneToOneField):
cls = 'factory.SubFactory'
rel =
rel_factory = '{0}Factory'.format(rel)
cls = 'factory.UNKNOWN'
#import pdb
print ' {name} = {cls}({args})'.format(, cls=cls, args=', '.join(args))
print '' # two lines between class definitions
print '# TODO: you also need to create and add imports for the '\
'following related factories: {0}'.format(', '.join(needed_factories - created_factories))
Copy link

vkurup commented Aug 7, 2015

Google brought me here! Updated to Python 3 (just making print a function) and it still works:

Thanks Tobias!

Copy link

Thanks Tobias! Google also brought me here, was a super helpful gist to get factory boy setup on a project the way I wanted.

Copy link

Tobias thank you ) I have been importing my class with factories and they are run two times((. And use name == main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment