Login

Format transition middleware

Author:
limodou
Posted:
March 2, 2007
Language:
Python
Version:
Pre .96
Score:
1 (after 1 ratings)

Note: This is a testing middleware. This snippets may be changed frequently later.

What's it

Sometimes I thought thow to easy the output data into another format, except html format. One way, you can use decorator, just like:

@render_template(template='xxx')
def viewfunc(request,...):

And the output data of viewfunc should be pure data. And if want to output json format, you should change the decorator to:

@json_response
def viewfunc(request,...):

I think it's not difficult. But if we can make it easier? Of cause, using middleware.

So you can see the code of process_response, it'll judge the response object first, if it's an instance of HttpResponse, then directly return it. If it's not, then get the format of requst, if it's json format, then use json_response() to render the result.

How to setup request.format? In process_request you and see, if the request.REQUEST has a format (you can setup it in settings.py with FORMAT_STRING option), then the request.format will be set as it. If there is not a such key, then the default will be json. So in your view code, you can just return a python variable, this middleware will automatically render this python variable into json format data and return.

For 0.2 it support xml-rpc. But it's very different from common implementation. For server url, you just need put the same url as the normal url, for example:

http://localhost:8000/booklist/ajax_list/?format=xmlrpc

Notice that the format is 'xmlrpc'. A text client program is:

from xmlrpclib import ServerProxy
server = ServerProxy("http://localhost:8000/booklist/ajax_list/?format=xmlrpc", verbose=True)
print server.booklist({'name':'limodou'})

And the method 'booklist' of server is useless, because the url has include the really view function, so you can use any name after server. And for parameters of the method, you should use a dict, and this dict will automatically convert into request.POST item. For above example, {'name':'limodou'}, you can visit it via request.POST['name'] .

For html format, you can register a format_processor callable object in request object. And middleware will use this callable object if the format is html.

Intall

Because the view function may return non-HttpResponse object, so this middleware should be installed at the end of MIDDLEWARE_CLASSES sections, so that the process_response of this middleware can be invoked at the first time before others middlewares.

And I also think this mechanism can be extended later, for example support xml-rpc, template render later, etc, but I have not implemented them, just a thought.

Options

FORMAT_STRING used for specify the key name of format variable pair in QUERY_STRING or POST data, if you don't set it in settings.py, default is 'format'. DEFAYLT_FORMAT used for default format, if you don't set it in settings.py, default is 'json'.

Reference

Snippets 8 ajax protocol for data for json_response

 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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# Author: [email protected]
# version: 0.2
# Format the request and response from/to json and other format
#
# Update:
#  0.1 support json format
#  0.2 support xmlrpc, html format 
#

from django.http import HttpResponse
from utils.ajax import json_response
from django.conf import settings

class FormatMiddleware(object):
    def process_request(self, request):
        format_string = getattr(settings, 'FORMAT_STRING', 'format')
        format = request.GET.get(format_string, '')
        if format:
            request.format = format.lower() #could be "json", "xmlrpc", etc
        else:
            request.format = getattr(settings, 'DEFAULT_FORMAT', 'json')
        if request.format == 'xmlrpc':
            import xmlrpclib
            p, u = xmlrpclib.getparser()
            p.feed(request.raw_post_data)
            p.close()
            
            args = u.close()
            if len(args) > 0:
                args = args[0]
                if not isinstance(args, dict):
                    xml = xmlrpclib.dumps(xmlrpclib.Fault(-32400, 'system error: %s' % 'Arguments should be a dict'), methodresponse=1)				
                    return HttpResponse(xml, mimetype='text/xml; charset=utf-8')
                    
                old = request.POST._mutable
                request.POST._mutable = True
                for k, v in args.items():
                    request.POST[k] = v
                request.POST._mutable = old
            
    def process_response(self, request, response):
        if isinstance(response, HttpResponse):
            return response
        elif request.format == 'json':
            return json_response(response)
        elif request.format == 'xmlrpc':
            import xmlrpclib
            try:
            	xml = xmlrpclib.dumps((response,), methodresponse=1)
            except Exception, e:
            	xml = xmlrpclib.dumps(xmlrpclib.Fault(-32400, 'system error: %s' % e), methodresponse=1)				
            return HttpResponse(xml, mimetype='text/xml; charset=utf-8')
        elif request.format == 'html':
            if hasattr(request, 'format_processor'):
                return request.format_processor(response)
            else:
                return HttpResponse(response)
        raise Exception, 'Not support this format [%s]' % request.format

More like this

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

Comments

Please login first before commenting.