Troubleshooting

General Django Troubleshooting Techniques

While some specific Django problems are addressed in this guide, some problems may require additional investigation to resolve. Here are some common strategies for resolving problems with Django applications.

Reviewing Django Logs in Real Time

You can review the logs of a Django application as they are recorded using tail with the log file. To review the logs in real time:

  1. Open an SSH session.
  2. Switch to the user logs directory. Enter cd $HOME/logs/user and press Enter.
  3. Enter tail -f error_django_app.log, where django_app is the name of the Django application as it appears in the control panel and press Enter.

New additions to the error log will automatically appear on screen. You can now access the site and see any log entries as they appear.

See also

Accessing Logs

Using the DEBUG Setting

Django has a built-in debug mode, provided by the DEBUG setting in settings.py. When DEBUG is enabled and an exception is raised, a detailed debugging output (including a stack trace) is rendered instead of attempting to render the 500 template.

Warning

Do not leave DEBUG set to True during normal operation. In addition to showing users unnecessary and potentially compromising configuration details in error pages, the DEBUG setting also causes Django to consume significantly more memory, which may exceed plan allotments.

To enable the Django DEBUG setting:

  1. Open an SSH session.
  2. Open settings.py for the Django application. Typically, this file is found in $HOME/webapps/django_app/project/project.
  3. If it already exists, edit the line containing DEBUG = False to DEBUG = True. Otherwise, add a new line containing DEBUG = True to the file.
  4. Restart the Django application.

Now, when an error occurs, a stack trace, settings information, and other valuable data is provided instead of rendering an error page. To force the appearance of the Django debugging page, simply add an assert False to a view and attempt to access it.

Using the Django Debug Toolbar

The Django Debug Toolbar is a pluggable Django middleware to help examine a request and response in the browser.

To install and enable the Django Debug Toolbar:

  1. Install the Django Debug Toolbar.

    1. Open an SSH session.
    2. Switch to the Django application directory. Enter cd $HOME/webapps/django_app, where django_app is the name of the application as it appears in the WebFaction control panel, and press Enter.
    3. Add the Django application’s Python directory to PYTHONPATH. Enter export PYTHONPATH=$PYTHONPATH:$HOME/webapps/django_app/lib/python2.7/ and press Enter.
    4. Install the Django Debug Toolbar with easy_install. Enter easy_install-2.7 --install-dir=$HOME/webapps/django_app/lib/python2.7/ --script-dir=$HOME/webapps/django_app/bin/ django-debug-toolbar and press Enter.
  2. Configure the Django Debug Toolbar for use with your Django project.

    1. Open $HOME/webapps/django_app/project/project/settings.py in a text editor, where project is the name of the Django project.

    2. Add debug_toolbar.middleware.DebugToolbarMiddleware to MIDDLEWARE_CLASSES. For example, edit the default MIDDLEWARE_CLASSES from:

      MIDDLEWARE_CLASSES = (
          'django.middleware.common.CommonMiddleware',
          'django.contrib.sessions.middleware.SessionMiddleware',
          'django.contrib.auth.middleware.AuthenticationMiddleware',
      )
      

      to

      MIDDLEWARE_CLASSES = (
          'django.middleware.common.CommonMiddleware',
          'django.contrib.sessions.middleware.SessionMiddleware',
          'django.contrib.auth.middleware.AuthenticationMiddleware',
          'debug_toolbar.middleware.DebugToolbarMiddleware',
      )
      

      Note

      Please see the Django Debug Toolbar’s README for more information on the order of MIDDLEWARE_CLASSES.

    3. Set which IP addresses may see the Django Debug Toolbar by adding INTERNAL_IPS setting. Insert INTERNAL_IPS = ('address',) where address is the address from which you will be accessing the Django application.

    4. Add debug_toolbar to INSTALLED_APPS. For example, edit the default INSTALLED_APPS from:

      INSTALLED_APPS = (
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.sites',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          # Uncomment the next line to enable the admin:
          # 'django.contrib.admin',
          # Uncomment the next line to enable admin documentation:
          # 'django.contrib.admindocs',
      )
      

      to

      INSTALLED_APPS = (
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.sites',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          # Uncomment the next line to enable the admin:
          # 'django.contrib.admin',
          # Uncomment the next line to enable admin documentation:
          # 'django.contrib.admindocs',
          'debug_toolbar',
      )
      
    5. Save and close the file.

  3. Restart the Django application.

Now, when accessing the Django application from an IP address specified in INTERNAL_IPS, the Django Debug Toolbar will appear on the right side of the page.

About manage.py runserver

Django’s manage.py includes the runserver command that provides a simple, lightweight web server for use while developing Django applications. While neither intended nor recommended for production use, runserver can be configured for development use on a WebFaction server.

Warning

Production use of runserver is not supported and strongly discouraged. runserver is intended as a development aid. runserver does not provide sufficient security, stability, and performance for production use.

From the Django documentation regarding runserver:

DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through security audits or performance tests. (And that’s how it’s gonna stay. We’re in the business of making Web frameworks, not Web servers, so improving this server to be able to handle a production environment is outside the scope of Django.)
  1. Create a custom application listening on a port.
    1. Log in to the control panel.
    2. Click Domains / websites ‣ Applications. The list of applications appears.
    3. Click the Add new application button. The Create a new application form appears.
    4. In the Name field, enter a name for the application.
    5. In the App category menu, click to select Custom.
    6. In the App type menu, click to select Custom app (listening on port).
    7. If applicable, in the Machine menu, click to select a web server.
    8. Click the Save button. The application is created and added to the list of applications.
    9. Make a note of the port number assigned to the application. It is required in a later step.
  2. Create a website entry for the custom application.
  3. Start the Django development server.
    1. Open an SSH session to your account.
    2. Switch to the directory of the Django project. Enter cd $HOME/webapps/django_app/project, where django_app is the name of the Django application as it appears in the WebFaction control panel and project is the name of the Django project, and press Enter.
    3. Enter python manage.py runserver port, where port is the port number assigned to the custom application, and press Enter.

You can now access the Django site with a web browser. The Django development server output will appear in the SSH session.

Fixing ImportError: No module named... Exceptions

Python will raise an ImportError exception whenever it cannot find a particular package or module named in an import statement. This is typically caused by the named module not appearing in Python’s module search path. For example, this error sometimes happens while attempting to run manage.py.

To correct the problem, the offending module needs to be added to the Python search path. In the case of Django module errors, you will need to add $HOME/webapps/django_app/lib/python2.7 to the Python module search path. To learn more about methods you can use to add to the Python search path, please see Fixing ImportError Exceptions.

Fixing Internal Server Errors

Django will return an HTTP status code of 500, an Internal Server Error, when Django encounters runtime errors in a view, such as a syntax error or a view failing to return an object that Django expects.

Closely related to errors in view logic is that Django itself will raise the TemplateDoesNotExist exception when an error is encountered in a view, the DEBUG setting is set to False and a 500.html template is not available.

The following two sections will help your resolve errors in your views and fix Django’s TemplateDoesNotExist exception for Internal Server Errors.

Fixing View Errors

When you encounter an Internal Server Error in your Django application, your foremost concern should be to fix your application so that it does not return an HTTP status code of 500. The best web applications respond to problems gracefully, without dumping an ugly error on the user.

The first step in fixing a view error is to identify the cause of the problem. A stack trace of the error will automatically be written to your Django application’s error log.

If the stack trace doesn’t provide you with the information you need to solve the problem, you can set DEBUG to True in your settings.py file. When DEBUG is True, a stack trace and detailed configuration information is output to the browser when the error occurs. However, be sure to set DEBUG to False when you are finished debugging: the debug output contains sensitive information (like file paths and configuration options) and SQL queries are retained in memory, vastly increasing your application’s memory consumption.

Finally, once you’ve found the source of the error in your view, be sure to update your Django application’s suite of tests to keep the error from creeping back into your code.

Fixing TemplateDoesNotExist for Internal Server Errors

Many Django installations raise an additional exception, TemplateDoesNotExist, when an error is encountered. Typically this happens when an error occurs while processing a view, no 500.html template is found, and the DEBUG setting is set to False.

The default error page (provided by Apache) contains this text:

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator, [no address given] and inform them of the time the error occurred, and anything you might have done that may have caused the error.

While the error is not described in detail on the page, the error log for the application will look something like this:

[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1] mod_wsgi (pid=11586): Exception occurred processing WSGI script '/home/username/webapps/django/myproject/myproject/wsgi.py'.
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1] Traceback (most recent call last):
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]   File "/home/username/webapps/django/lib/python2.7/django/core/handlers/wsgi.py", line 241, in __call__
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]     response = self.get_response(request)
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]   File "/home/username/webapps/django/lib/python2.7/django/core/handlers/base.py", line 122, in get_response
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]     return self.handle_uncaught_exception(request, resolver, sys.exc_info())
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]   File "/home/username/webapps/django/lib/python2.7/django/core/handlers/base.py", line 166, in handle_uncaught_exception
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]     return callback(request, **param_dict)
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]   File "/home/username/webapps/django/lib/python2.7/django/views/defaults.py", line 23, in server_error
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]     t = loader.get_template(template_name) # You need to create a 500.html template.
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]   File "/home/username/webapps/django/lib/python2.7/django/template/loader.py", line 81, in get_template
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]     source, origin = find_template_source(template_name)
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]   File "/home/username/webapps/django/lib/python2.7/django/template/loader.py", line 74, in find_template_source
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1]     raise TemplateDoesNotExist, name
[Fri Nov 13 14:04:35 2009] [error] [client 127.0.0.1] TemplateDoesNotExist: 500.html

To resolve this problem, create a new template named 500.html in your templates directory. To see what directories are currently configured as template directories:

  1. Open an SSH session.
  2. Enter cd $HOME/webapps/django_app/project/project, where django_app is the name of your Django application as it appears in the control panel and project is the name of your Django project, and press Enter.
  3. Enter python -c "import settings; print settings.TEMPLATE_DIRS" and press Enter.

Then, in one of the template directories, create a new file named 500.html. The file can be as simple as this sample 500.html:

<html>
    <head>
        <title>Server Error</title>
    </head>
    <body>
        <h1>Sorry!</h1>
        <p>Sorry, the server has encountered an error.</p>
    </body>
</html>

though it’s recommended that you add contact information to your server error page, so your users can reach you in the event of a problem.

Reducing Django Start-Up Time

Django may be slow to respond on the first few requests, while mod_wsgi loads and starts the Django application. To reduce these delays, modify your Django application’s mod_wsgi configuration. See Reducing Application Start-Up Time for step-by-step directions.

Reducing Memory Consumption

Django applications can be tuned to consume more or less memory. Consider the following strategies to reduce your Django application’s memory consumption, but note that some configuration changes—such as allocating fewer processes or maximum requests—may have a negative impact on overall performance. You may want to experiment with different combinations of configuration values to suit your memory and performance needs.

  • Set DEBUG to False: When Django’s DEBUG setting is set to True, SQL queries and other extra data are kept in memory. See Using the DEBUG Setting for more details on what DEBUG does and how to change it.

  • Serve static media with a Static-only application: Serving site media, like style sheets, JavaScript, CSS files, and Djano admin media, with the Django application is an inefficient use of memory. Instead, let the system-wide nginx-process serve static media with a static application.

  • Reduce the number of objects loaded into memory: Use the features of Django’s ORM to avoid loading more objects than you need into memory.

    For example, suppose you want to retrieve all the users from your database with the first name John. Instead of fetching all user objects and sifting through for those you need, like this:

    # Don't do this!
    subset_of_users = []
    for user in Users.objects.all():
        if user.first_name == 'John':
            subset_of_users.append(user)
    

    try using Django’s QuerySet API to load only the objects you need:

    subset_of_users = Users.objects.filter(first_name__exact='John')
    

    Not only is the QuerySet version fewer lines code, but it uses less memory, too.

Reset an Admin Password

To reset a Django admin account password:

  1. Open an SSH session to your account.

  2. Switch to the Django project directory. Enter cd $HOME/webapps/django_app/project, where django_app is the name of the Django application as it appears on the control panel and project is the name of the project, and press Enter.

  3. Start the Django shell. Enter python2.X manage.py shell, where X is the minor Python version number associated with your Django application and press Enter.

  4. Import the User class. Enter from django.contrib.auth.models import User and press Enter.

  5. Get the object of User for which to change the password. Enter u = User.objects.get(username__exact='username') and press Enter.

  6. Change the password. Enter u.set_password('password'), where password is the new password, and press Enter.

    See also

    See Strengthening Passwords for important information about choosing passwords.

  7. Save the change. Enter u.save() and press Enter.

  8. Exit the shell. Press Control + D.

You can now log in with the new password.

Accessing REMOTE_ADDR

When a Django application’s Apache instance proxies requests to Django, the REMOTE_ADDR header is not set with the clients’s IP address. Instead, the IP address is available as the first IP address in the comma separated list in the HTTP_X_FORWARDED_FOR header. When you need REMOTE_ADDR, access the first of HTTP_X_FORWARDED_FOR‘s IP addresses instead.

Alternatively, you can use this middleware class to automatically set REMOTE_ADDR to the value of HTTP_X_FORWARDED_FOR

class WebFactionFixes(object):
    """Sets 'REMOTE_ADDR' based on 'HTTP_X_FORWARDED_FOR', if the latter is
    set.

    Based on http://djangosnippets.org/snippets/1706/
    """
    def process_request(self, request):
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            ip = request.META['HTTP_X_FORWARDED_FOR'].split(",")[0].strip()
            request.META['REMOTE_ADDR'] = ip