<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: djugl</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/djugl.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2009-12-05T17:10:59+00:00</updated><author><name>Simon Willison</name></author><entry><title>What's coming in Django 1.2 (presentation notes)</title><link href="https://simonwillison.net/2009/Dec/5/django/#atom-tag" rel="alternate"/><published>2009-12-05T17:10:59+00:00</published><updated>2009-12-05T17:10:59+00:00</updated><id>https://simonwillison.net/2009/Dec/5/django/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://simonwillison.net/static/2009/djugl-december.html"&gt;What&amp;#x27;s coming in Django 1.2 (presentation notes)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I wrote up some background notes for the talk on Django 1.2 I gave at DJUGL last week.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/djugl"&gt;djugl&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/speaking"&gt;speaking&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/my-talks"&gt;my-talks&lt;/a&gt;&lt;/p&gt;



</summary><category term="django"/><category term="djugl"/><category term="python"/><category term="speaking"/><category term="my-talks"/></entry><entry><title>Debugging Django, a slidecast</title><link href="https://simonwillison.net/2008/May/25/debugging/#atom-tag" rel="alternate"/><published>2008-05-25T14:47:02+00:00</published><updated>2008-05-25T14:47:02+00:00</updated><id>https://simonwillison.net/2008/May/25/debugging/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.slideshare.net/simon/debugging-django/"&gt;Debugging Django, a slidecast&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I used SlideShare’s slidecast tool for the first time to synchronize audio of my Django London User Group talk with the slides. The talk included several live demos which aren’t represented in the slides so it’s a bit piecemeal in places.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/debugging"&gt;debugging&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/djugl"&gt;djugl&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/slidecast"&gt;slidecast&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/slideshare"&gt;slideshare&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/speaking"&gt;speaking&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/my-talks"&gt;my-talks&lt;/a&gt;&lt;/p&gt;



</summary><category term="debugging"/><category term="django"/><category term="djugl"/><category term="slidecast"/><category term="slideshare"/><category term="speaking"/><category term="my-talks"/></entry><entry><title>Debugging Django</title><link href="https://simonwillison.net/2008/May/22/debugging/#atom-tag" rel="alternate"/><published>2008-05-22T00:35:40+00:00</published><updated>2008-05-22T00:35:40+00:00</updated><id>https://simonwillison.net/2008/May/22/debugging/#atom-tag</id><summary type="html">
    &lt;p&gt;I gave a talk on Debugging Django applications at &lt;a href="http://upcoming.yahoo.com/event/546918/"&gt;Monday's inaugural meeting&lt;/a&gt; of DJUGL, the London Django Users Group. I wanted to talk about something that wasn't particularly well documented elsewhere, so I pitched the talk as "Bug Driven Development" - what happens when Test Driven Development goes the way of &lt;a href="http://www.shipmentoffail.com/fails/2008/04/horse-vs-car-fail/"&gt;this unfortunate pony&lt;/a&gt;.&lt;/p&gt;

The slides &lt;a href="http://www.slideshare.net/simon/debugging-django/"&gt;are up on SlideShare&lt;/a&gt;, but don't provide quite enough context so I'm going to cover the tips in full here.

&lt;h4&gt;Making the most of the error page&lt;/h4&gt;

&lt;p&gt;Django's default error page is great - it provides a detailed traceback with local variables, lets you expand out the lines of code around the problem, provides a plain text exception suitable for e-mailing to colleagues and even a one-click button to send details to &lt;a href="http://dpaste.com/"&gt;http://dpaste.com/&lt;/a&gt; so you can go and talk about the error on IRC. It also serves the same purpose as &lt;a href="http://www.php.net/phpinfo"&gt;phpinfo()&lt;/a&gt; - it shows you your application's settings, the GET, POST and COOKIE data from the request and the all important META fields assembled from the HTTP environment (great for remembering how to miss-spell HTTP_REFERER).&lt;/p&gt;

&lt;p&gt;Useful tip number one is that you can trigger the error page from any view just by adding the following line:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;assert False&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can serve up an expression with the assertion as well; it will be displayed at the top of the error page:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;assert False, request.GET&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One particularly useful place to use this is when you are building a complex form. If you want to see the data that was submitted, drop an assert False in to the view that the form targets and use the error page to inspect the data.&lt;/p&gt;

&lt;h4&gt;Logging to the development server console&lt;/h4&gt;

&lt;p&gt;If you want to know what's going on inside a view, the quickest way is to drop in a print statement. The development server outputs any print statements directly to the terminal; it's the server-side alternative to a JavaScript alert().&lt;/p&gt;

&lt;p&gt;If you want to be a bit more sophisticated with your logging, it's worth turning to Python's logging module (part of the standard library). You can configure it in your settings.py:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;import logging
logging.basicConfig(
    level = logging.DEBUG,
    format = '%(asctime)s %(levelname)s %(message)s',
)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then call it from any of your views:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;def my_view(request):
    import logging
    logging.debug("A log message")
    ...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again, this will log things to the terminal where the development server is running. If you want to log things to a file you can do so by extending the basicConfig call:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;logging.basicConfig(
    level = logging.DEBUG,
    format = '%(asctime)s %(levelname)s %(message)s',
    filename = '/tmp/myapp.log',
    filemode = 'w'
)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can then use &lt;samp&gt;tail -f /tmp/myapp.log&lt;/samp&gt; to see log lines being appended to that file in real-time. This can be used in production as well as development.&lt;/p&gt;

&lt;p&gt;The above just scratches the surface of Python's logging module; with a bit of &lt;a href="http://docs.python.org/lib/module-logging.html" title="Loggingi facility for Python"&gt;digging around in the documentation&lt;/a&gt; you can use it to rotate log files, send log messages over the network and even POST log events to an HTTP server somewhere.&lt;/p&gt;

&lt;p&gt;Often you find yourself dealing with an error that only occurs in certain circumstances - a function might be called from dozens of different places in your program but only runs in to trouble in a very specific case. You can use the &lt;a href="http://docs.python.org/lib/module-traceback.html"&gt;traceback module&lt;/a&gt; to log the current stack, which will allow you to tell how a function was called when something went wrong:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;import logging, traceback, pprint

def my_buggy_function(arg):
    ...
    if error_condition:
        stack = pprint.pformat(traceback.extract_stack())
        logging.debug('An error occurred: %s' % stack)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The tuple returned by &lt;code class="python"&gt;traceback.extract_stack()&lt;/code&gt; includes line numbers, function names and paths to Python files so you can use it to reconstruct a good amount of information about your program.&lt;/p&gt;

&lt;h4&gt;Using the debugger&lt;/h4&gt;

&lt;p&gt;By far the most powerful weapon in my debugging toolkit is the Python debugger, &lt;a href="http://docs.python.org/lib/module-pdb.html"&gt;pdb&lt;/a&gt;. Again, this ships with the standard library so there's nothing extra to install. pdb is a command line debugger (if you want a GUI options include &lt;a href="http://sourceforge.net/projects/pyeclipse/"&gt;PyEclipse&lt;/a&gt; and &lt;a href="http://www.activestate.com/Products/komodo_ide/index.mhtml"&gt;Komodo&lt;/a&gt;, but I haven't used either myself). There are a bunch of ways to activate pdb, but the most straight forward is to simply drop the following line directly in to a Django view function:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;import pdb; pdb.set_trace()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you try to load that page in your browser, the browser will hang - the page will appear to be loading extremely slowly. What's actually happened is the developer server has paused execution and thrown up the pdb interface - you can switch over to your console and start interacting directly with the server mid view.&lt;/p&gt;

&lt;p&gt;Did I mention you should never, ever leave this on in production?&lt;/p&gt;

&lt;p&gt;So, you've got a hung development server and a pdb prompt. What can you do with it? The answer is pretty much anything. I won't provide a full pdb tutorial here (&lt;a href="http://www.onlamp.com/pub/a/python/2005/09/01/debugger.html"&gt;this is a good introduction&lt;/a&gt;), but the commands I find most useful are the following:&lt;/p&gt;

&lt;dl&gt;
    &lt;dt&gt;list&lt;/dt&gt;
    &lt;dd&gt;Shows the lines of source code around your current point of execution. You can run it multiple times to increase the amount of source code displayed.&lt;/dd&gt;
    &lt;dt&gt;n&lt;/dt&gt;
    &lt;dd&gt;Execute the next line&lt;/dd&gt;
    &lt;dt&gt;s&lt;/dt&gt;
    &lt;dd&gt;Same as n, but steps in to any functions that are called. You can quickly get lost in a twisty maze of code with this command, but that's OK because...&lt;/dd&gt;
    &lt;dt&gt;r&lt;/dt&gt;
    &lt;dd&gt;Continues execution until the current function returns&lt;/dd&gt;
    &lt;dt&gt;u&lt;/dt&gt;
    &lt;dd&gt;Goes UP one level in the stack - so you can see the function that called the function you are currently in&lt;/dd&gt;
    &lt;dt&gt;d&lt;/dt&gt;
    &lt;dd&gt;Goes DOWN again&lt;/dd&gt;
    &lt;dt&gt;locals()&lt;/dt&gt;
    &lt;dd&gt;not a pdb command, but handy for seeing what's in your current scope&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;The pdb docs have &lt;a href="http://www.python.org/doc/current/lib/debugger-commands.html"&gt;a full list of commands&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The pdb prompt doubles up as a full Python interactive shell, so you can not only access variables but you can modify them, call functions and generally mess around with the internals of your application as much as you like, while it's running. It's kind of a poor man's imitation of being a Smalltalk developer.&lt;/p&gt;

&lt;p&gt;Remember though, the whole time you're messing around in pdb your browser is still stuck there, waiting for the HTTP request to come back. If you hit "c" (for continue) your application will kick in again, the request will be served and your browser will breathe a sigh of relief.&lt;/p&gt;

&lt;p&gt;Thankfully you don't have to use pdb in a way that freezes your development server; it also works great in the interactive shell. If you've got a buggy function, one way to explore it is to run it interactively, then use the following idiom:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;&amp;gt;&amp;gt;&amp;gt; def function_that_raises_an_exception():
...   assert False
... 
&amp;gt;&amp;gt;&amp;gt; function_that_raises_an_exception()
Traceback (most recent call last):
  File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in &amp;lt;module&amp;gt;
  File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 2, in function_that_raises_an_exception
AssertionError
&amp;gt;&amp;gt;&amp;gt; import pdb; pdb.pm()
&amp;gt; &amp;lt;stdin&amp;gt;(2)function_that_raises_an_exception()
(Pdb)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;pdb.pm()&lt;/code&gt; stands for post-mortem, and is probably my favourite feature of the debugger - it lets you jump back in to debug the most recently raised exception, even if you hadn't imported pdb at the time the exception was raised.&lt;/p&gt;

&lt;p&gt;One last pdb tip: you can use it to debug Python command line scripts such as Django's custom &lt;samp&gt;./manage.py&lt;/samp&gt; commands. The trick is to run the script like this:&lt;/p&gt;

&lt;p&gt;&lt;samp&gt;python -i manage.py buggy_command&lt;/samp&gt;&lt;/p&gt;

&lt;p&gt;The &lt;samp&gt;-i&lt;/samp&gt; argument causes Python to drop in to the interactive prompt after executing the script. If the script raised an exception, you can then use &lt;code&gt;pdb.pm()&lt;/code&gt; to debug it.&lt;/p&gt;

&lt;h4&gt;Handling errors in production&lt;/h4&gt;

&lt;p&gt;Django's default behaviour in production (that is, when the DEBUG setting is set to False) is to e-mail exception reports to anyone listed in the ADMINS section. You can also turn on e-mail reports on every 404 error with the SEND_BROKEN_LINK_EMAILS setting, which will send them to addresses in the MANAGERS setting. As far as I know these settings don't do anything else - they're a pretty ancient bit of Django.&lt;/p&gt;

&lt;p&gt;On a high traffic site you probably don't want to be e-mailed on every server error. One neat alternative is David Cramer's &lt;a href="http://code.google.com/p/django-db-log/"&gt;django-db-log&lt;/a&gt;, which logs exceptions to a database table. It cleverly uses an MD5 hash of the traceback to aggregate many reports of the same error. More importantly though, it acts as a really straight forward example of how to use Django middleware's process_exception hook to roll your own error reporting. Take a look &lt;a href="http://code.google.com/p/django-db-log/source/browse/trunk/djangodblog/__init__.py"&gt;at the code&lt;/a&gt; to see how simple this is.&lt;/p&gt;

&lt;h4&gt;More useful middleware&lt;/h4&gt;

&lt;p&gt;In the talk I demoed a couple of other handy pieces of middleware. The first was the &lt;a href="http://www.djangosnippets.org/snippets/727/"&gt;ProfilerMiddleware&lt;/a&gt; (one of several profiling tools on &lt;a href="http://www.djangosnippets.org/"&gt;Django Snippets&lt;/a&gt;) which allows you to add &lt;samp&gt;?prof&lt;/samp&gt; to the end of any URL to see the output of Python's &lt;a href="http://docs.python.org/lib/module-profile.html"&gt;cProfile module&lt;/a&gt; run against that request. The second is one that I've just released: &lt;a href="http://www.djangosnippets.org/snippets/766/"&gt;DebugFooter&lt;/a&gt;, which adds a footer showing exactly which templates were loaded from where (handy for debugging complex template paths) as well as every executed SQL query and how long each one took.&lt;/p&gt;

&lt;h4&gt;Abusing the test client&lt;/h4&gt;

&lt;p&gt;A final tip for exploring your application interactively is to learn to use &lt;a href="http://www.djangoproject.com/documentation/testing/"&gt;Django's TestClient&lt;/a&gt;. Although designed for use in unit tests, this tool is equally useful for use at the interactive prompt. It allows you to simulate an in-process request against your application from within your Python code. Here's an example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;&amp;gt;&amp;gt;&amp;gt; from django.test.client import Client
&amp;gt;&amp;gt;&amp;gt; c = Client()
&amp;gt;&amp;gt;&amp;gt; response = c.get(&amp;quot;/&amp;quot;) # The homepage
&amp;gt;&amp;gt;&amp;gt; response
&amp;lt;django.http.HttpResponse object at 0x2300470&amp;gt;
&amp;gt;&amp;gt;&amp;gt; print response
Vary: Cookie
Content-Type: text/html; charset=utf-8

&amp;lt;!DOCTYPE HTML PUBLIC &amp;quot;-//W3C//DTD HTML 4.01//EN&amp;quot;
    &amp;quot;http://www.w3.org/TR/html4/strict.dtd&amp;quot;&amp;gt;
&amp;lt;html&amp;gt;
...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The response object you get back is the &lt;code class="python"&gt;HttpResponse&lt;/code&gt; returned by the view, ready to be explored interactively.&lt;/p&gt;

&lt;p&gt;There's another function from the unit testing tools that can help with interactively exploring an application: &lt;code class="python"&gt;setup_test_environment()&lt;/code&gt;. This function monkey-patches in some additional hooks used by the unit tests, including one that intercepts template render calls and adds information on them to the request object. Here's an example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;&amp;gt;&amp;gt;&amp;gt; from django.test.utils import setup_test_environment
&amp;gt;&amp;gt;&amp;gt; setup_test_environment()
&amp;gt;&amp;gt;&amp;gt; from django.test.client import Client
&amp;gt;&amp;gt;&amp;gt; c = Client()
&amp;gt;&amp;gt;&amp;gt; response = c.get(&amp;quot;/&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; response.template
[&amp;lt;django.template.Template object at 0x2723dd0&amp;gt;,
 &amp;lt;django.template.Template object at 0x2723f30&amp;gt;,
 &amp;lt;django.template.Template object at 0x273ee10&amp;gt;]
&amp;gt;&amp;gt;&amp;gt; response.context
[ list of Context objects ]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This allows you to explore not just the HTML returned by a view, but also the templates and contexts that were used to render it.&lt;/p&gt;

&lt;h4&gt;Your tips welcome&lt;/h4&gt;

&lt;p&gt;If you have any useful tips on debugging Django applications, please share them in the comments on this entry.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/debugging"&gt;debugging&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/djugl"&gt;djugl&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/middleware"&gt;middleware&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/my-talks"&gt;my-talks&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="debugging"/><category term="django"/><category term="djugl"/><category term="middleware"/><category term="my-talks"/><category term="testing"/></entry><entry><title>Django Users Group London meetup, 19th of May</title><link href="https://simonwillison.net/2008/May/2/djugl/#atom-tag" rel="alternate"/><published>2008-05-02T12:19:45+00:00</published><updated>2008-05-02T12:19:45+00:00</updated><id>https://simonwillison.net/2008/May/2/djugl/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://upcoming.yahoo.com/event/546918/"&gt;Django Users Group London meetup, 19th of May&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The inaugural meeting of DJUGL will be on the 19th of May at the Capital Radio building in Leicester Square, sponsored by GCap Media. Three presentations starting at 7pm (I’ll be giving one of them), then on to the pub. Sign up on EventWax; there are only 70 places.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/djugl"&gt;djugl&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/events"&gt;events&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gcap"&gt;gcap&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gcapmedia"&gt;gcapmedia&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/london"&gt;london&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;



</summary><category term="django"/><category term="djugl"/><category term="events"/><category term="gcap"/><category term="gcapmedia"/><category term="london"/><category term="python"/></entry></feed>