Where to put Django startup code?

24,925

Solution 1

Write middleware that does this in __init__ and afterwards raise django.core.exceptions.MiddlewareNotUsed from the __init__, django will remove it for all requests :). __init__ is called at startup by the way, not at the first request, so it won't block your first user.

There is talk about adding a startup signal, but that won't be available soon (a major problem for example is when this signal should be sent)

Related Ticket: https://code.djangoproject.com/ticket/13024

Update: Django 1.7 includes support for this. (Documentation, as linked by the ticket)

Solution 2

In Django 1.7+ if you want to run a startup code and,

1. Avoid running it in migrate, makemigrations, shell sessions, ...

2. Avoid running it twice or more

A solution would be:

file: myapp/apps.py

from django.apps import AppConfig

def startup():
    # startup code goes here

class MyAppConfig(AppConfig):
    name = 'myapp'
    verbose_name = "My Application"
    def ready(self):
        import os
        if os.environ.get('RUN_MAIN'):
            startup()

file: myapp/__init__.py

default_app_config = 'myapp.apps.MyAppConfig'

This post is using suggestions from @Pykler and @bdoering

Solution 3

If you were using Apache/mod_wsgi for both, use the WSGI script file described in:

http://blog.dscpl.com.au/2010/03/improved-wsgi-script-for-use-with.html

Add what you need after language translations are activated.

Thus:

import sys

sys.path.insert(0, '/usr/local/django/mysite')

import settings

import django.core.management
django.core.management.setup_environ(settings)
utility = django.core.management.ManagementUtility()
command = utility.fetch_command('runserver')

command.validate()

import django.conf
import django.utils

django.utils.translation.activate(django.conf.settings.LANGUAGE_CODE)

# Your line here.
django.core.management.call_command('syncdb', interactive=False)

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()

Solution 4

You can create a custom command and write your code in the handle function. details here https://docs.djangoproject.com/en/dev/howto/custom-management-commands/

Then you can create a startup script that runs the django server then executes your new custom command.

Solution 5

If you are using mod_wsgi you can put it in the wsgi start app

Share:
24,925
Attila O.
Author by

Attila O.

SRE @ Google.

Updated on July 09, 2022

Comments

  • Attila O.
    Attila O. almost 2 years

    I'd like to have these lines of code executed on server startup (both development and production):

    from django.core import management
    management.call_command('syncdb', interactive=False)
    

    Putting it in settings.py doesn't work, as it requires the settings to be loaded already.

    Putting them in a view and accessing that view externally doesn't work either, as there are some middlewares that use the database and those will fail and not let me access the view.

    Putting them in a middleware would work, but that would get called each time my app is accessed. An possible solution might be to create a middleware that does all the job and then removes itself from MIDDLEWARE_CLASSES so it's not called anymore. Can I do that without too much monkey-patching?

  • Attila O.
    Attila O. about 14 years
    Thanks for the quick response. This is exactly what I need.
  • Attila O.
    Attila O. about 14 years
    That'd look a little different as I use twod.wsgi. Also, I'd like to do this on the dev server too. And I wouldn't go as low level as apache. The idea is that I might not want to give the app developer ssh access to the server, but let him use the django admin by putting it in his startup code.
  • KillianDS
    KillianDS over 12 years
    This is a bad choice at it relies on a wrapper script around the server startup. What if someone forgets to start the server without the script?
  • Attila O.
    Attila O. over 12 years
    I agree with @KillianDS. Still, it is a possibility. But then you'd have to use your wrapper as an entry point to the server, which may be any platform, mod_wsgi, app engine, tornado, etc.
  • Michael
    Michael over 12 years
    According to stackoverflow.com/questions/6791911/…, this can be problematic. It is suggested there to put the start-up function in urls.py
  • Andrei
    Andrei over 12 years
    Both middleware and urls.py do not run the startup code for management commands. Is there a better option?
  • krizajb
    krizajb over 11 years
    I am still getting multiple startup calls (printing random string, prints it multiple times)
  • KillianDS
    KillianDS over 11 years
    @krizajB: note that this answer was written with django 1.0 or 1.1 in mind, there are currently better solutions available and maybe this solution is even not valid anymore in django 1.4. I'd update the answer with more recent techniques, but I've not done much django development recently so if someone knows a better modern technique, feel free to add it.
  • krizajb
    krizajb over 11 years
    Been googling whole day, couldn't find anything that would work .. At least not for my case :(
  • Diego Barbaresco
    Diego Barbaresco over 11 years
    This doesn't seem to work in python 1.4... Any recommendations/workarounds?
  • krizajb
    krizajb over 11 years
    As suggested by Michael, that seems to be the best solution at the moment (Django 1.4). There seems to be an update which isn't yet merged to the main branch, see github.com/ptone/django/blob/… . Oh, also be sure if you are using mod_wsgi to set it to deamon mode and if needed run it as a single process. See more here: code.google.com/p/modwsgi/wiki/IntegrationWithDjango keyword: WSGIDaemonProcess.
  • tr00st
    tr00st almost 10 years
    Found this question working from the other direction in 1.7 - ie: DB calls from AppConfig.ready() can have some really awkward side-effects. Specific use case is hooking up dynamic Models based on DB contents, so when tests are run, one can very quickly run into issues with missing tables. The middleware workaround may work best here, as it will only be called on the first request - ie: when we're on the right DB. We can then hook up something on the testing side to ensure that the init code gets called there too.
  • Klaas van Schelven
    Klaas van Schelven over 9 years
    Note that the linked solution for Django 1.7 explicitly warns against running any SQL (which appears to have been the original question).
  • Incerteza
    Incerteza about 9 years
    Again, how to do that - write the code to be executed on startup of the App?
  • binithb
    binithb over 4 years
    who will set the environment varianle RUN_MAIN?
  • Joseph Bani
    Joseph Bani about 4 years
    @binithb apparently django does at runtime