Login

Ajax API class

Author:
kcarnold
Posted:
June 13, 2008
Language:
Python
Version:
.96
Score:
2 (after 2 ratings)

Whip up an AJAX API for your site in a jiffy:

class MySite(AJAXApi):
  @AJAXApi.export
  def hello(request):
      return {'content': self.get_content()}

  def get_content(self):
    return 'Hello, world!'

  urlpatterns += MySite().url_patterns()

(the example needs the JSON encoding middleware of snippet 803 to work.)

The secret is that bound instance methods are callable too, so work as views. (Most Django people only use functions, or sometimes classes with __call__, as view functions.)

You get implicit type dispatch off that self object. So you could subclass MySite, change get_content, and still use the same hello method.

See (django-webapp)[http://code.google.com/p/django-webapp/] for a REST-ish Resource class using this same idea.

You can clearly do better than my func_to_view, and also make a better decorator than exported (so you can actually say @exported('name') def function() etc.). This is more of a proof of concept that should work for most people.

Caveat: I've changed a few things since I last really tested this.

(psst, this also works for non-AJAX views too.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from django.conf.urls.defaults import url
from django.utils.decorators import wraps

def func_to_view(f):
    @wraps(f)
    def _dec(request, *a, **kw):
        kwargs = dict(kw)
        for k, v in request.REQUEST.items():
            kwargs[str(k)] = v
        return f(request, *a, **kwargs)
    return _dec

class AjaxAPI(object):
    def url_patterns(self, prefix=''):
        attrs = ((name, getattr(self, name)) for name in dir(self)
                 if not name.startswith('__'))
        methods = ((name, method) for (name, method) in attrs if callable(method))

        res = []
        for name, method in methods:
            exported = getattr(method, 'exported', False)
            if not exported: continue
            if isinstance(exported, basestring):
                export_name = exported
            else:
                export_name = name # Default to exporting by function name
            res.append(url('^%s%s/$' % (prefix, export_name),
                           func_to_view(method)))
        return res

    @staticmethod
    def export(f, name=True):
        f.exported = name
        return f

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 1 week ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 9 months, 4 weeks ago
  5. Help text hyperlinks by sa2812 10 months, 3 weeks ago

Comments

Please login first before commenting.