-
-
Save easherma/8b31da2f9d49678af33e6c95da01e81e 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.core.management.base import BaseCommand | |
from django.db.models import fields | |
from django.db.models.fields import related | |
from django.apps import apps | |
class Command(BaseCommand): | |
help = """Generate factory-boy factories for the given app""" | |
def add_arguments(self, parser): | |
parser.add_argument("app", type=str) | |
def handle(self, *args, **options): | |
app = options["app"] | |
app = apps.get_app_config(app) | |
models = app.get_models(app) | |
app_label = app.label | |
print( | |
""" | |
import factory | |
import datetime | |
import {models} as {app_label}_models | |
# import other requried factories here | |
""".format( | |
models=app.get_models, app_label=app.label | |
) | |
) | |
needed_factories = set() | |
created_factories = set() | |
for model in models: | |
print( | |
""" | |
class {model_name}Factory(factory.django.DjangoModelFactory): | |
class Meta: | |
model = {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): | |
continue | |
if field.default != fields.NOT_PROVIDED: | |
print( | |
" # skipped field {0} ({1}) with default value ({2})".format( | |
field.name, field.__class__.__name__, field.default | |
) | |
) | |
continue | |
if field.blank or field.null: | |
print( | |
" # skipped blank or nullable field {0} ({1})".format( | |
field.name, field.__class__.__name__ | |
) | |
) | |
continue | |
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" | |
args.append("0") | |
elif isinstance(field, fields.EmailField): | |
cls = "factory.Sequence" | |
args.append( | |
'lambda n: "{0}-{1}-{{}}@example.com".format(n)'.format( | |
model_slug, field.name | |
) | |
) | |
elif isinstance(field, fields.CharField) or isinstance( | |
field, fields.TextField | |
): | |
cls = "factory.Sequence" | |
args.append( | |
'lambda n: "{0}-{1}-{{}}".format(n)'.format( | |
model_slug, field.name | |
) | |
) | |
elif isinstance(field, fields.DateTimeField): | |
cls = "factory.fuzzy.FuzzyNaiveDateTime" | |
args.append( | |
"datetime.datetime.now() - datetime.timedelta(days=365)" | |
) | |
elif isinstance(field, fields.DateField): | |
cls = "factory.fuzzy.FuzzyDate" | |
args.append("datetime.date.today() - datetime.timedelta(days=365)") | |
elif isinstance(field, related.ForeignKey) or isinstance( | |
field, related.OneToOneField | |
): | |
cls = "factory.SubFactory" | |
rel = field.rel.to.__name__ | |
rel_factory = "{0}Factory".format(rel) | |
needed_factories.add(rel_factory) | |
args.append(rel_factory) | |
else: | |
cls = "factory.UNKNOWN" | |
args.append(field.__class__.__name__) | |
print( | |
" {name} = {cls}({args})".format( | |
name=field.name, cls=cls, args=", ".join(args) | |
) | |
) | |
created_factories.add( | |
"{model_name}Factory".format(model_name=model.__name__) | |
) | |
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) | |
) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment