How To Run Django Initialization Code Only Once On Startup?


How To Run Django Initialization Code Only Once On Startup?

Let’s say you have a piece of initialization code, that you want to run only once, when Django is starting up. What’s the proper way to handle this? Where should you put this code?

Django provides a hook for running initialization code: you can override the AppConfig.ready method in your app. This method will be called only once, after the app has been initialized. For some tasks you might also consider executing a custom management command before starting Django.

In this article I will show you how and when to apply these solutions, and also point out some important caveats.

Common Use Cases

What type of initialization code would you typically want to run in a Django app? One common use case is executing some kind of db syncing, writing to the filesystem or doing some other attached resource initialization. These do not necessarily need to be run as part of the Django process, so you can run this type of code as part of the deployment process before starting the Django application server (more on this later).

Another class of startup code is when you need to initialize some in-memory object. A good example is setting up Django signals.

Setting Up the Initialization Code

Custom Management Command

If you do not need to run your code as part of the Django process (for example you want to update some rows in the database or copy/move some files around), you can simply create a custom django management command, and run it before startup.

Defining your own custom command is quite simple, you can just create a directory called management/commands inside your app’s directory.

You can register commands by adding files in this directory, for example:

# my_app/management/commands/my_custom_startup_command.py

from django.core.management.base import BaseCommand, CommandError

class Command(BaseCommand):
    help = 'My custom startup command'

    def handle(self, *args, **kwargs):
        try:
            # put startup code here
        except:
            raise CommandError('Initalization failed.')

You can run this command like so (add this to your deployment script, before starting the application server):

python manage.py my_custom_startup_command

This is my recommendation for defining startup code, unless you need to initialize something in memory, in the context of the Django app server.

AppConfig.ready() Hook

Django defines a hook for application initialization: the AppConfig.ready(). This approach is useful if you want to run some code inside the Django appserver process (setting up signals for example).

To do this, just override the ready method in your app’s config. Assuming that it is defined as MyAppConfig in my_app/apps.py, it would look something like this:

# my_app/apps.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'My App'
    def ready(self):
        # put your startup code here

Other Possible Solutions

There are plenty of other places where you could put your code (settings.py, models.py, urls.py), as Django loads a lot of files on startup, but you should avoid putting initialization codes in any other place except the above mentioned.

One reason for this is that it is not guaranteed, that the app is properly initialized at the time it executes your code. Even if it seems to be working now, but there’s no guarantee that it won’t break in future Django releases.

Another reason is simply code organization best practices and the ease of debugging. Generally, it’s not a good idea for import statements to have side effects other than making the imported objects accessible. Breaking that rule can make mocking, testing and debugging quite complicated.