Set up and Load Initial Data in Django

Introduction
Sometimes there's a need to have a set of initial data once we spin up our application. Reasons vary, but the need is there. Django provides two ways of setting up and loading this initial data to our database.

  • Using Fixtures
  • Using Migrations

For the purposes of this brief explanation, we will have a model, Book in our app called Main

# main/models.py

from django import models

class Book(models.Model):
    name = models.CharField(max_length=50)
    author = models.CharField(max_length=20)

Using Fixtures

A fixture is a collection of data that Django knows how to import into a database. In this specific approach to fixtures, our data is not going to be loaded automatically. We are going to create the fixture by hand, then load them by running a command.

Creating Fixtures

First, we need a folder to hold our fixtures. We can create a folder called fixtures at app level (in our app Main), or we can have all our fixtures at project level by defining FIXTURE_DIRS in our settings.py.
FIXTURE_DIRS should contain a list of directories where Django should look for fixtures.

In this case, I have set FIXTURE_DIRS at project level to have it as:

# my_project/setting.py

FIXTURE_DIRS =  BASE_DIR / "fixtures"

Create the directory fixtures at project level. Here, we are going to create our fixtures, which can be any of the following formats:

  • JSON
  • XML
  • YAML

We are going to use JSON, so within our fixtures directory, let's create a file book.json. I prefer to name the fixtures after the app that their models belong to.

# fixtures/cars.json

[
  {
    "model": "main.book",
    "pk": 1,
    "fields": {
      "name": "Atomic Habits",
      "author": "James Clear",
    }
  },
  {
    "model": "main.book",
    "pk": 2,
    "fields": {
      "name": "Permanent Record",
      "author": "Edward Snowden",
    }
  }
]

Loading data

Since we have created our fixtures by hand, we need to call the individually to load the data:

python manage.py loaddata fixture_file_name

python manage.py loaddata cars.json

Using Migrations

In this method, we are going to generate our own empty migration by running the following command:

syntax: python manage.py makemigrations --empty appname

As previously mentioned, our app name is Main, and our model is Book, so our command should be:

python manage.py makemigrations --empty main

This command will generate an automatically migration file, within your app's migrations folder. The file should be of a similiar format to this:

# Generated by Django 3.0.11 on 2021-12-15 08:35
from django.db import migrations

class Migration(migrations.Migration):

    dependencies = [
        ('main', '0001_initial'),
    ]

    operations = [
    ]

Create Function to add data

We need to create a function that will add the data. This function must have two arguments, which are:

  • App Registry - A registry of all your apps, including
    historical versions of their models.

  • Schema Editor - This is what is used to manually
    effect database schema changes, (enforce changes to database)

With this is in mind, let's write our function:

def load_initial_data(apps, schema_editor):
    # get our model
    # get_model(appname, modelname)
    book_model = apps.get_model('main', 'Book')
    book_model.objects.create (
        name = "Atomic Habits", author = "James Clear"
        )
    book_model.objects.create (
        name = "Permanent Record", author = "Edward Snowden"
        )

This function should be within your migration file, as follows:

# Generated by Django 3.0.11 on 2021-12-15 08:35
from django.db import migrations

def load_initial_data(apps, schema_editor):
    # get our model
    # get_model(appname, modelname)
    book_model = apps.get_model('main', 'Book')
    book_model.objects.create (
        name = "Atomic Habits", author = "James Clear"
        )
    book_model.objects.create (
        name = "Permanent Record", author = "Edward Snowden"
        )

class Migration(migrations.Migration):

    dependencies = [
        ('main', '0001_initial'),
    ]

    operations = [
    ]

We can now add our load_initial_data function to the operations list in our migration file:

operations = [
   migrations.RunPython(load_initial_data),
]

Your complete migrations file should be similar to this:

# Generated by Django 3.0.11 on 2021-12-15 08:35
from django.db import migrations

def load_initial_data(apps, schema_editor):
    # get our model
    # get_model(appname, modelname)
    book_model = apps.get_model('main', 'Book')
    book_model.objects.create (
        name = "Atomic Habits", author = "James Clear"
        )
    book_model.objects.create (
        name = "Permanent Record", author = "Edward Snowden"
        )

class Migration(migrations.Migration):

    dependencies = [
        ('main', '0001_initial'),
    ]

    operations = [
       migrations.RunPython(load_initial_data),
    ]

Load data

Since our data is in a migration file, we need to migrate in order to load it. So, we simply run:

python manage.py migrate

20