How Django Works (2) Built-in Server, Autoreload
Django's built-in server
Django comes with a built-in server for development and testing purpose.The command to start the built-in server is
python manage.py runserver
Autoreload
One notable feature of the built-in server is its ability to automatically reload once a file is changed. Accord to Official document, "The development server automatically reloads Python code for each request, as
needed. You don’t need to restart the server for code changes to take effect.
However, some actions like adding files don’t trigger a restart, so you’ll
have to restart the server in these cases." The feature can be shut off by --noreload.
This blog will examine in implementation detail how autoreload is implemented and how autoreload is used by Django built-in server.
The file that implements autoreload is site-packages/django/utils/autoreload.py
if django is installed. Or you can find it at https://github.com/django/django/blob/master/django/utils/autoreload.py
Django's built-in server uses autoreload
The autoreload is used in site-packages/django/core/management/commands/runserver.pyclass Command(BaseCommand):
...
def run(self, **options): """ Runs the server, using the autoreloader if needed """ use_reloader = options.get('use_reloader') if use_reloader: autoreload.main(self.inner_run, None, options) else: self.inner_run(None, **options) def inner_run(self, *args, **options): threading = options.get('use_threading') shutdown_message = options.get('shutdown_message', '') quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C' self.stdout.write("Performing system checks...\n\n") self.check(display_num_errors=True) self.check_migrations() now = datetime.now().strftime('%B %d, %Y - %X') if six.PY2: now = now.decode(get_system_encoding()) self.stdout.write(now) self.stdout.write(( "Django version %(version)s, using settings %(settings)r\n" "Starting development server at http://%(addr)s:%(port)s/\n" "Quit the server with %(quit_command)s.\n"
- By default, use_reloader is True, run will call inner_run indirectly through autoreload module
- If --noreload is used use_reloader is set to False, run will call inner_run directly.
How autoreload works
- The main process spawn a new process and wait for the result from spawn. While the child process is executed, main process is blocked.
- Child process starts a new thread that carry out real work (in the case of Django inner_run).
- Child process's main thread loops and checks weather any file from sys.modules has been changed, if so main thread exit with exit value set to 3.
- Upon return from spawn, main process checks if exit value is 3. If so, main process spawn a child process again. Otherwise, the main process exit.
I've written a small case that debugs the whole process using pudb. The autoreload file was also modified to remove references to Django.
https://github.com/druckenclam/code4blogs/tree/master/Django_Autoreload