Sunday, January 8, 2017

Django - 015 - Django's pretty error pages

Take moment to admire the fine web application we have made so far- now let's break it! Let us deliberately introduce a Python error into our views.py file by commenting out the
offset = int(offset) lines in the hours_ahead view:

def hours_ahead(request, offset):
  #try:
  #   offset = int(offset)
  #except ValueError:
   #  raise Http404()
  dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
  html = "<html><body> In %s hour(s), it will be %s. </body></html>" % (offset,dt)
  return HttpResponse(html)

Load up the development server and navigate to /time/plus/3/. You will see an error page with a significant amount of information, including a TypeError message displayed at the very top: unsupported type for timedelta hours component: str



What happened? Well, the datetime.timedelta function expects the hours parameter to be an integer, and we commented out the bit of code that converted offset to an integer. That caused datetime.timedelta to raise the TypeError. It is the typical kind of small bug that every programmer runs into at somepoint. The point of this example was to demonstrate Django's error pages. Take some time to explore the error page and get to know the various bits of information it gives you. Here are some things to notice:

  • At the top of the page, you get the key information about the exception: the t ype of exception, any parameters to the exception (the unsupported type message in this case), the file in which the exception was raised, and the offending line number.
  • Under the key exception information, the page displays the full Python traceback for this exception. This is similar to the standard traceback you get in Python's command-line interpreter, except it is more interactive. For each level (frame) in the stack, Django displays the name of the file, the function/method name, the line number, and the source code of that line.
  • Click the line of source code (in dark gray), and you will see several lines from before and after the erroneous line, to give you context. Click Local vars under any frame in the stack to view a table of all local variables and their values , in that frame, at the exact point in the code at which the exception was raised. This debugging information can be of great help!
  • Note the switch to copy-and-paste view text under the Traceback header. Click those words, and the traceback will switch to an alternate version that can be easily copied and pasted. Use this when you want to share your exception traceback with others to get technical support - such as the kind folks in the Django IRC chat room or on the Django users mailing list. 
  • Underneath, the Share this traceback on a public website button will do this work for you in just one click. Click it to post the traceback to dpaste (for more information visit http://www.dpaste.com/), where you will get a distinct URL that you can share with other people.
  • Next, the Request information section includes a wealth of information about the incoming web request that spawned the error: GET  and POST information, cookie values, and meta information, such as CGI headers. 
  • Following to the Request Information section, the Settings section lists all of the settings for this particular Django installation.


The Django error page is capable of displaying more information in certain special cases, such as the case of template syntax errors. For now, uncomment the offset = int(offset) lines to get the view function working properly again.

The Django error page is also really useful if you are the type of programmer who likes to debug with the help of carefully placed print statements.

At any point in your view, temporarily insert an assert False to trigger the error page. Then, you can view the local variables and state of the program. Here is an example, using the hours_ahead view:

def hours_ahead(request, offset):
  try:
     offset = int(offset)
  except ValueError:
     raise Http404()
  dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
  assert False
  html = "<html><body> In %s hour(s), it will be %s. </body></html>" % (offset,dt)
  return HttpResponse(html)

Finally, it is obvious that much of this information is sensitive - it exposes the innards of your Python code and Django configuration. - and it would be foolish to show this information on the public internet. A malicious person can use it to attempt to reverse-engineer your web application and do nasty things. For that reason, the Django error page is only displayed when Django project is in debug mode. For now, just know that every Django project is in debug mode automatically when you start it. (Sounds familiar? The Page not Found errors, described earlier in this chapter, work the same way.)

No comments:

Post a Comment