One of the many issues which one must overcome with Jinja2 is using it with 3rd party modules. A lot of these already have built-in views, and many have yet to realize the benefit of class-based views. Today, I’m going to explain how we approached this for DjangoSpot (GitHub) and django-registration.
The goal, as always, is the write the least amount of code. However, extending function-based views is now an easy task. So our approach involves using some tricky Python code (thanks to Chris Leary for the ideas!).
Let’s talk about requirements real quick. You’ll need Django 1.1 (or newer), Jinja2, and Coffin 0.3.1 or newer (which as of writing, is not on PyPi).
First off, we’re going to use inspect.getsource to retrieve source code for functions, and exec to evaluate that source code. One thing to note here, is that if the function you are trying to modify is using a decorator, it may not be possible to get the actual functions source code. Some, however, can be obtained by using my_function.func_var_name.
So let’s take a look at our urls.py in djangospot.accounts.urls:
import inspect from registration import urls exec inspect.getsource(urls)\ .replace('django.contrib.auth', 'coffin.contrib.auth')
As you can see above, we’re importing the urls from django registration, and then running getsource on it. This gets us the source code from that entire file. From there, we simply swap out django.contrib.auth for our drop-in coffin.contrib.auth.
Next up, we need to handle the views. It’s a similar approach, except we’re not doing any tricky string replacement:
import inspect from registration.views import * from coffin.shortcuts import render_to_response from coffin.template import RequestContext exec inspect.getsource(activate) exec inspect.getsource(register)
What we’re doing here, is getting the source code for the actual methods, and simply executing it. To ensure we have all the needed imports, we first import everything from the registration.views. Afterwards, we replace the render_to_response and RequestContext imports with the ones made available in Coffin.
Overall, it’s a fairly sketchy process, but it works beautiful. We approach the problem in a similar fashion with Coffin and the generic and contrib views in there.
