Login

Generic view mixing that allows output to JSON, HTML, HTML SNIPPETS

Author:
danielsokolowski
Posted:
August 4, 2011
Language:
Python
Version:
1.3
Score:
0 (after 0 ratings)

Adding this mixing to your existing class based views allows for outputting of queries into any registered serialzier format -- very handy for dynamic JS based GUI on the JSON format.

This generic view mixing was created on our last project which required a fancy JS based user experience and yet also needed to be accessible through non JS enabled browsers.

 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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
""" 
Author: Daniel Sokolowski ([email protected])

Generic Views used by the project
"""
from django.http import HttpResponse
from django.core import serializers
from django.views.generic.base import TemplateResponseMixin
from django.http import Http404
from django.core.exceptions import ImproperlyConfigured


class MultiFormatResponseMixin(TemplateResponseMixin):
    """
    Render http response in in either in HTML (default), HTML snippet or any serializer that is supported format. 
    The rendering output is determined by ``output`` request GET variable  as follows:
    
    ``?output=serialzier_<serializer_name> OR <html> OR <inc.html>`` - OPTIONAL: defaults to html 
    
    <serializer_name> part of the GET variable is passed to the Django serialzier frame with additional ``serializer_options``
    defined on your custom class views. Hence if one has added additional serialziers they are fully supported.
    
    If <serializer_name> dosen't exist or output serializer format is not supported or serializer_options are missing
     a 404 response is generated.
     
    To use simple define your class based view as follows and based on ?output=<value> different format is returned:
    
    ```
    class AdCategoryListView(MultiFormatResponseMixin, ListView):
    
    context_object_name="adcategories_list"
    serializer_options = {
                    'json': {
                            'fields': ['locations'],
                            'extras': ['get_firstmedia_url']
                            },
                    'geojson': {
                            'fields': ['locations'],   
                            }
                    }
    
    def get_queryset(self):
        return AdCategory.objects.filter(parent_category__isnull = True) 
    
    ...
    ...
    
    ```
    
    Template naming convention for different outputs:
    
    ```?output=serialzier_json``` = NO TEMPLATE - response is output of calling json serialzier on the query
    ```?output=serialzier_foobar``` = NO TEMPLATE - response is output of calling foobar serialzier on the query
                            
                            
    ```?output=html``` = <templates>/<app_label>/<model name><template_name_suffix>.html
    ```?output=inc.html``` = <templates>/<app_label>/<model name><template_name_suffix>.inc.html
    
    Suggested aditional serialziers: 
        GEOJSON - http://djangosnippets.org/snippets/2434/)
        DjangoFullSerializers http://code.google.com/p/wadofstuff/wiki/DjangoFullSerializers 
    
    """
    def render_to_response(self, context):
        # Look for a 'format=<foo>' GET argument if dosen't exist then do normal html Template Response mixin response
        if self.request.GET.get('output','html') == 'html':
            return super(MultiFormatResponseMixin, self).render_to_response(context) # call original ListView.render_to_response()
        elif self.request.GET.get('output','') == 'inc.html':
            opts = self.get_queryset().model._meta
            self.template_name = "%s/%s%s.inc.html" % (opts.app_label, opts.object_name.lower(), self.template_name_suffix)
            return super(MultiFormatResponseMixin, self).render_to_response(context) # call original ListView.render_to_response()
        
        output = self.request.GET.get('output')
        if not 'serializer_' in output:
            raise Http404
        
        """
        Check we are configured properly first - we do the check here so that adding this mixin
        dosen't prevent original view logic from executing 
        """
        if not hasattr(self, 'serializer_options'):
            raise ImproperlyConfigured(u"'%s' must define 'serializer_options'" % self.__class__.__name__)

        serializer = output.split('_')[1] # grap serialzier name

        """ if serialzier is not supported or it's options not specified in view's serializer_options raise 404"""
        if not serializer in serializers.get_serializer_formats() or serializer not in self.serializer_options:
            raise Http404
            
        output = self.request.GET.get('output','')
        query = self.get_queryset()
        if hasattr(self, 'get_object'): # if get_object attribute exists than we should filter to that object only
            query = query.filter(pk=self.get_object().pk)
        
        content = serializers.serialize(serializer, query, **self.serializer_options[serializer])
        #return HttpResponse(content, content_type='application/%s' % serializer)
        return HttpResponse(content)
       

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 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, 7 months ago

Comments

Please login first before commenting.