Quickstart

Requirements, Installation & Configuration

You will need at least Python 2.5+ and Django 1.0+

Firstly install the package from pypi:

pip install aino-utkik

Secondly, you need to setup the dispatcher by replacing all imports in all your urls.py. Before:

from django.conf.urls.defaults import

After:

from utkik.dispatch import

Anything after the import on the same row should be kept intact. If you are brave you can place your self in your project root and issue:

find -name urls.py | xargs perl -p -i -e 's/from\ django\.conf\.urls.defaults/from utkik.dispatch/g'

Usage

Dispatcher

Now you are ready to use the utkik dispatcher. This allows you to reference a class based view based from Django 1.3 Class-based generic views or utkik.View as a string in your urls.py (or any other class based view that has an entry point method called dispatch). Assuming that your class resides in myapp.views.Home and that myapp is in INSTALLED_APPS you may reference it as follows:

from utkik.dispatch import *

urlpatterns = patterns('',
    (r'^$', 'myapp.Home'),
)

Alternatively you can reference it with a more accurate string. You can always reference a class based view even if it’s not in INSTALLED_APPS this way:

from utkik.dispatch import *

urlpatterns = patterns('',
    (r'^$', 'myapp.views.Home'),
)

utkik.View

I will describe the main ideas here and if you have the time please look through the source code, it is really small.

Firstly the handler for an allowed request is defined as a method that has the same name as the HTTP request method, only lower cased. So a GET request will try to call a get method on the class and a POST method a post and so on. A method is allowed only if the class has a corresponding lower case named attribute on the class. But because not everyone keeps those method names in their head there is an additional attribute in the class that controls if the method should be allowed or not and that is methods. By default this is set to ['GET', 'POST' , 'PUT', 'DELETE'] thus allowing only GET, POST, PUT and DELETE. If you want to allow anything else you first have to add that method name to this list and then create a method with the lower case name on the class.

So basically you do all your stuff in the handler or conduct it from there, for example MyView.get. The handler gets passed any additional arguments that is parsed from the urls.py but not the request. The request object is accessed through the class instance it self self.request. So your get handler might start something like:

def get(self, slug):
    ...

At the end of the handler you can either return a valid HttpResponse or you don’t return anything. If you don’t return anything the self.render method will be called. This method renders the first existing template returned from get_template_names() with self.get_context_data() as context data and returns the result. Unless template_name nor ajax_template_name is defined get_template_names() returns a list of automatically computed template names. This is how this is done: First we try to figure out the current app_label then we use the current name of the view class but using lower-case letters and underscores thus ProductList will become product_list and s on. From these variables we put together a path for the template: << app_label >>/<< un-cameled class name >>.html and for ajax calls this is << app_label >>/<< un-cameled class name >>.ajax.html. You have the option to override this, although I dicourage doing so. The class properties are: template_name and ajax_template_name.

But wait there is more! In your view you can reference an object representing the context as self.c. You can set stuff to the context as follows:

self.c.news = get_object_or_404(News.objects, slug=slug)

The self.get_context_data by default returns this context object as a dictionary. Adding a decorator is a no brainer too, just add it to the self.decorators list. If you want to add a decorator for GET but not for POST, that is a specific decorator per handler you can use yet another decorator utkik.decorators.handler_decorator. This decorator accepts normal view function decorators like django.contrib.auth.decorators.login_required. Example:

from django.contrib.auth.decorators import login_required
from functional import wraps
from utkik.decorators import handler_decorator, require_ajax
from utkik import View, HttpJSONResponse

def mydecorator(f):
    """function view decorator"""
    @wraps(f):
    def wrapper(request, *args, **kwargs):
        if not request.user.email.endswith('@aino.se'):
            return HttpResponse(status=402)
        return f(request, *args, **kwargs)
    return wrapper

class Home(View):
    @handler_decorator(login_required, mydecorator)
    def get(self):
        pass

    @handler_decorator(require_ajax):
    def post(self):
        return HttpJSONResponse({ "message": "rock my pony" })

Now, lets bake another simple view example:

from django.contrib.auth.decorators import login_required
from utkik import View
from news.models import News

class NewsDetail(View):
    decorators = [ login_required ]

    def get(self, slug):
        self.c.news = get_object_or_404(News.objects, slug=slug)

That is all there is to it! You are not returning anything from the handler and thus letting self.render do the work.

For more please read the code and see the examples.