JULY 05, 2011
Extending templates from a specific Django app
A while ago (well, actually a long time ago since I had this blog post laying around as a draft, until I stumbled across a stack overflow question that this post would answer) I wanted to customize Django's admin app, by adding a link to a statistics page that I had built, on the index.html page of the admin app.
I could have copied the index.html from the templates directory in the admin app, to my project's templates directory and added my link, but this would have given me a maintenance task to keep Django's admin templates up to date in future versions. So what I really wanted to do was to define my own admin/index.html file in the project's templates directory, and then in my index template extend the index template from the admin app. However this isn't supported by Django be default.
When I searched the web I found all sort of solutions to the problem, some involving symlinking the admin's index.html to another path and then extending the symlink, but that wasn't an option for me since I develop on both Windows and Unix, and besides, it didn't feel like a very clean solution.
Finally I found very nice template loader on djangosnippets.org which solved my problem! It allows you to extend a template from a specific Django app by using the following syntax:
{% extends "admin:admin/index.html" %}
As you can see, I specify the app where the template resides before the colon. The admin/index.html, in my project's template directory, that I finally ended up with looks like this:
{% extends "admin:admin/index.html" %} {% block sidebar %} {{block.super}} <div> < h1>Statistics< /h1> < a href="/admin/station/stats/">Published Stations< /a> </div> {% endblock %}
Now I won't have to change anything if the Django admin app's index.html is updated in a newer version of Django, unless the sidebar block is removed, or something similar.
Also, if you decide to use this trick, don't forget to add the template loader to the TEMPLATE_LOADERS list in your project's settings.py file.
APRIL 22, 2010
Python urllib2 timeout issue
I use urllib2 from Python's standard library, in quite a few projects. It's quite nice, but the documentation isn't very comprehensive and it always makes me feel like I'm programming Java once I want to do something more complicated than just open an URL and read the response (i.e. handling redirect responses, reading response headers, etc).
Anyway, the other day I found - if not a bug - then at least an undocumented issue. Since Python 2.6, urllib2 provides a way to set the timeout time, like in the following code where the timeout is set to 2.5 seconds:
import urllib2 try: response = urllib2.urlopen("http://google.com", None, 2.5) except URLError, e: print "Oops, timed out?"
If no timeout is specified, the global socket timeout value will be used, which by default is infinite.
The above code will catch almost every timeout, but the problem is that you might still get a timeout raised as a totally different exception:
File "/usr/lib/python2.4/socket.py", line 285, in read data = self._sock.recv(recv_size) File "/usr/lib/python2.4/httplib.py", line 460, in read return self._read_chunked(amt) File "/usr/lib/python2.4/httplib.py", line 495, in _read_chunked line = self.fp.readline() File "/usr/lib/python2.4/socket.py", line 325, in readline data = recv(1) socket.timeout: timed out
The solution is to catch this other exception, thrown by python's socket lib, as well:
import urllib2 import socket try: response = urllib2.urlopen("http://google.com", None, 2.5) except URLError, e: print "Oops, timed out?" except socket.timeout: print "Timed out!"
Hopefully this will save someone else some headache :).
MARCH 03, 2010
Favorite Django Tips
A few months ago I found a really useful Stack Overflow Question. Here are my favorites from the answers.
Use render_to decorator instead of render_to_response
This decorator is found in the app django annoying, and is a very nice shortcut for declaring what template a view should render.
Instead of returning the response of render_to_response, you just return a python dict which will be used as the template context for the template specified as argument to the @render_to decorator. If anything else than a dict is returned, normal view processing will occur, so this won't break redirects or any other cases where you might return a HttpResponse (for example normal render_to_response code).
Anyway, here is an example on how to use it:
@render_to("list.html") def list_posts(request): posts = BlogPost.objects.all() return {"blog_posts": posts}
This equals to:
def list_posts(request): posts = BlogPost.objects.all() return render_to_response('list.html', {'blog_posts': posts}, context_instance=RequestContext(request))
Update (22/4): Marcin Nowak notified me that the render_to decorator breaks Django Reusable App converions, so I made a fork of django-annoying where I modified the render_to decorator to support template_name and extra_context keyword arguments.
Load custom template tags in all templates
Custom template tags that you use all over your templates can be auto loaded. Just add the following in a module that is loaded (i.e. your urlconf if you want the template tags to be loaded for the whole project)
from django import template template.add_to_builtins('project.app.templatetags.custom_tag_module')
Use relative paths in settings.py
I hesitated about adding this tips, since I think it's quite obvious, but since so many people on Stack Overflow has voted it up, I guess there are people who use(d) absolute paths in their settings.py.
Don't use absolute paths in settings.py (i.e /home/jonatan/...), instead use relative paths so that the project will work wherever it resides.
import os.path TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), "templates"), )
ABOUT ME
My name is Jonatan Heyman, and I'm a programmer. I'm also a climber, and I listen to
a large number of indie pop tunes. You can read more about me on the about page.
