Easy Dummy Data For Django Development

written by Chris Goodwin on 2021-04-04

In this article I will show you how to easily get dummy data going for your Django project and I promise it is easier than you might expect!

I will be assuming the following is true:

  • You have a Django app with some models already built
  • You want to get some dummy data in that app easily
  • You want the data to appear realistic and not just lorum ipsum

As you might know from my testing django with managed and unmanaged models article I am a big fan of the factory_boy library. It does such a great job of giving us realistic data for our models without a lot of hassle - and once again, we'll lean on that library here for our dummy data.

This all gets broken down into three main sections: creating the factories, creating the commands and running the commands.

Let's get to it!

Open your Django project in your favorite IDE/editor (I prefer VSCode, if you like something else - leave a comment!)

Open your console and navigate to your Django project directory

Adding Factories with Factory Boy

With the assumption that you have a working application with existing models - let's add factory_boy to the mix so we can get some dummy data generated for us as needed.

STEP 1: From console run pip install factory_boy

I prefer to add factory_boy to my requirements-dev.txt file at this point - to make it easy on myself in the future. If you're not using requirements files - perhaps read my article on what are requirements files.

STEP 2: Create a factories.py file (important: ensure it is located in your app directory)

This file will give us all the control we need so our dummy data is realistic and randomized, just like it would be in the real world.

STEP 3: Create our "factories" (examples below of a Django model and the corresponding factory)

Standard Django Model(models.py):
class Thing(models.Model):
    last_login = models.DateTimeField(null=True)
    end_year = models.IntegerField()
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    username = models.CharField(max_length=30)
    email = models.CharField(max_length=75)
    active = models.BooleanField(default=False)
Factory_boy Model (factories.py):
class ThingFactory(factory.django.DjangoModelFactory):

    class Meta:
        model = yourapp.models.Thing

    last_login = factory.fuzzy.FuzzyDateTime(timezone.now())
    end_year = 2021
    first_name = factory.Faker("first_name")
    last_name = factory.Faker("last_name")
    username = factory.LazyAttribute(
        lambda a: "{0}.{1}".format(a.first_name, a.last_name).lower()
    )
    email = factory.LazyAttribute(
        lambda a: "{0}.{1}@test.com".format(a.first_name, a.last_name).lower()
    )
    active = True

Now when we call the factory like ThingFactory() it will generate a Thing model for us with random data. It can generate almost any random data you would want - check out the The factory_boy docs for more information and examples on how it generates that data.

Create the command to generate our data

Generating our own custom management commands is easy in Django! I am going to create a command we can call with python manage.py create_app_data

STEP 1: In your app directory create the following directories

Directory structure:

  • your_app_dir/management/commands/

STEP 2: Inside the commands directory create the following two files:

  • create_app_data.py
  • delete_app_data.py

Now we have added two commands to our project - so now we can write what they will do!

Our create_app_data.py should contain something like this:

from your_project.settings import is_debug
from your_app.factories import ThingFactory

class Command(BaseCommand):
    help="Creates dummy Things for our app"

    @transaction.atomic
    def handle(self, *args, **kwargs):
        # Check to ensure we are in an environment
        # where debug is True to avoid adding data
        # in a production environment
        if is_debug(os.environ.get("DJANGO_DEBUG")):
            # Create new Things for our app
            self.stdout.write("Creating the new Things for our app")
            for i in range(10):
                ThingFactory()
        else:
            self.stdout.write(
                """
                !!!We will not create the app data because DEBUG is set to
                False which may indicate a production environment!!!
                """
            )

Our delete_app_data.py should contain something like this:

from your_project.settings import is_debug
from your_app.models import Thing

class Command(BaseCommand):
    help="Deletes dummy Things for our app"

    # Using this decorator ensures that the SQL is bundled up and the commands are
    # ran together - speeding up the process
    @transaction.atomic
    def handle(self, *args, **kwargs):
        # Check to ensure we are in an environment
        # where debug is True to avoid deleting data
        # from a production environment
        if is_debug(os.environ.get("DJANGO_DEBUG")):
            # Delete Things from our app
            self.stdout.write("Deleting Things from our app")
            models = [Thing]
            for m in models:
                m.objects.all().delete()
        else:
            self.stdout.write(
                """
                !!!We will not delete the app data because DEBUG is set to
                False which may indicate a production environment!!!
                """
            )

A few additional notes about these commands:

  • I created a function in my settings.py file called is_debug that checks for an environment variable we pass to it - which in our case is DJANGO_DEBUG; we check that in our commands to hopefully prevent these commands from ever being ran in a production environment.

The is_debug setting looks like this:

def is_debug(environment_variable):
    """ Returns boolean for the string environment variable """
    return environment_variable.lower() in ["true", "True"]
  • In the delete_app_data.py file, I create a list of models so that in cases where we have created mulitple models worth of data in our create command, we can add the models there to delete those same models data.

Running the commands

At this point we have all the pieces in place to create some dummy data!

In your console (at the project level) you can run the following to create some dummy data:

python manage.py create_app_data

If you want to delete the dummy data you can run:

python manage.py delete_app_data

Additional Notes/Ideas/Takeaways

This is a great starting point to creating dummy data. If you wanted to use these commands in testing? You could!

# imports at the top of the file
from django.core import management

class YourTestCase(TestCase):
    def setUp(self):
        # This creates the dummy data for the test
        management.call_command(
            "create_app_data", verbosity=0
        )

You could also call the delete_app_data command from within the create_app_data command so it would essentially "reset" the data when you called create_app_data, a nice feature!

By using this method of creating dummy data, it allows for a lot of customization/flexibility and sets up your app with a lot of dummy data that will be useful when developing features locally.

I hope you have found this article helpful in understaning how to quickly/easily get dummy data setup for your Django Application!

I would love to hear from you in the comments below!

Cheers!

Did you find this article helpful?

Feel free to help me keep this blog going (with coffee)!