david / django-modelviews

Backup of an old repository with useful ideas. Initial goal: integrating REST to django admin (class-based views).

Clone this repository (size: 85.8 KB): HTTPS / SSH
$ hg clone http://code.welldev.org/django-modelviews
commit 40: 08ef53bf9dda
parent 39: 7bb34b38501f
branch: default
Moved responders into responders.py
Will Larson
2 years ago

Changed (Δ16.6 KB):

raw changeset »

generic/responders.py (230 lines added, 0 lines removed)

generic/rest_views.py (1 lines added, 225 lines removed)

Up to file-list generic/responders.py:

1
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
2
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotAllowed
3
from django.utils.feedgenerator import DefaultFeed, Atom1Feed, Rss201rev2Feed
4
from django.core.xheaders import populate_xheaders
5
from django.core.serializers import serialize
6
from django.shortcuts import render_to_response
7
from django.template import loader, RequestContext
8
9
class BaseResponder(object):
10
    def __init__(self, queryset):
11
        self.queryset = queryset
12
    
13
    def get_context_vars(self, context_vars):
14
        """
15
        Returns a dictionary of context vars, override if you need more.
16
        """
17
        return context_vars
18
19
    def list(self, request, paginate_by, allow_empty):
20
        """
21
        Renders a list of model objects to HttpResponse.
22
        """
23
        if paginate_by:
24
            paginator = QuerySetPaginator(self.queryset, paginate_by,
25
                                          allow_empty_first_page=allow_empty)
26
            page = request.GET.get('page', 1)
27
            try:
28
                page_number = int(page)
29
            except ValueError:
30
                if page == 'last':
31
                    page_number = paginator.num_pages
32
                else:
33
                    # Page is not 'last', nor can it be converted to an int.
34
                    raise Http404
35
            try:
36
                page_obj = paginator.page(page_number)
37
            except InvalidPage:
38
                raise Http404
39
            object_list = page_obj.object_list
40
        else:
41
            object_list = self.queryset
42
            paginator = None
43
            page_obj = None
44
            if not allow_empty and len(self.queryset) == 0:
45
                raise Http404
46
        return self.render_list(request, object_list, paginator, page_obj)
47
48
    def render_list(self, request, object_list, paginator, page_obj):
49
        """
50
        Renders the specified queryset. By the time it reaches this
51
        method the queryset has already been reduced to its appropriate
52
        paginated size, and successfully passed all "should this happen"
53
        logic (in the list method), and should be rendered with minimal
54
        fuss.
55
        """
56
        raise NotImplementedError(u"render_list() must be implemented by subclass.")
57
58
    def element(self, request, obj):
59
        raise NotImplementedError(u"element() must be implemented by subclass.")
60
61
    def create_success(self, request, new_obj, post_save_redirect):
62
        """
63
        Returns an HttpResonse, generally an HttpResponse redirect. This will
64
        be the final return value of the view and will only be called if the
65
        object was saved successfuly.
66
        """
67
        # Redirect to the new object: first by trying post_save_redirect,
68
        # then by obj.get_absolute_url; fail if neither works.
69
        if post_save_redirect:
70
            return HttpResponseRedirect(post_save_redirect % new_obj.__dict__)
71
        elif hasattr(new_obj, 'get_absolute_url'):
72
            return HttpResponseRedirect(new_obj.get_absolute_url())
73
        else:
74
            raise ImproperlyConfigured("No URL to redirect to from generic create view.")
75
76
    def update_success(self, request, obj, new_obj, post_save_redirect):
77
        """
78
        Returns an HttpResonse, generally an HttpResponse redirect. This will
79
        be the final return value of the view and will only be called if the
80
        object was saved successfuly.
81
        """
82
        # Redirect to the new object: first by trying post_save_redirect,
83
        # then by obj.get_absolute_url; fail if neither works.
84
        if post_save_redirect:
85
            return HttpResponseRedirect(post_save_redirect % new_obj.__dict__)
86
        elif hasattr(new_obj, 'get_absolute_url'):
87
            return HttpResponseRedirect(new_obj.get_absolute_url())
88
        else:
89
            raise ImproperlyConfigured("No URL to redirect to from generic create view.")
90
91
    def delete_success(self, post_save_redirect):
92
        return HttpResponseRedirect(post_save_redirect)
93
    
94
95
96
class HtmlResponder(BaseResponder):
97
    """
98
    HtmlResponder renders an object or a list of objects with the Django
99
    templating system.
100
    """
101
    def render_response(self, request, template, context_vars, mimetype=None):
102
        """
103
        Returns an HttpResponse for the given request, template object,
104
        dictionary of context variables, and optional mimetype.
105
        """
106
        context = RequestContext(request, context_vars)
107
        template = template.render(context)
108
        return HttpResponse(template, mimetype=mimetype)
109
    
110
    def get_template(self, opts, target='list'):
111
        """
112
        Returns a loaded template, the template_name depends of the model name.
113
        
114
        Examples::
115
        
116
            blog/post_list.html
117
            auth/user_detail.html
118
        """
119
        template_name = "%s/%s_%s.html" % (opts.app_label, opts.object_name.lower(), target)
120
        return loader.get_template(template_name)
121
122
    def render_list(self, request, object_list, paginator, page_obj):
123
        context_vars = self.get_context_vars({
124
            'object_list': object_list,
125
            'paginator': paginator,
126
            'page_obj': page_obj
127
        })
128
        opts = self.queryset.model._meta
129
        template = self.get_template(opts)
130
        return self.render_response(request, template, context_vars)
131
132
    def element(self, request, obj):
133
        """
134
        Renders single model objects to HttpResponse.
135
        """
136
        context_vars = self.get_context_vars({'object': obj})
137
        opts = self.queryset.model._meta
138
        template = self.get_template(opts, target='detail')
139
        response = self.render_response(request, template, context_vars)
140
        populate_xheaders(request, response, self.queryset.model, getattr(obj, opts.pk.name))
141
        return response
142
143
144
class FeedResponder(BaseResponder):
145
    feedgenerator_class = DefaultFeed
146
    def add_obj(self, feed, obj):
147
        """
148
        Wrapper for feed.add_item which compute title, link and description.
149
        """
150
        title = unicode(obj)
151
        if hasattr(obj, 'get_absolute_url'):
152
            link = obj.get_absolute_url()
153
        else:
154
            raise ImproperlyConfigured(\
155
                    "get_absolute_url function  is required for model %s." % \
156
                    self.queryset.model._meta.object_name.lower())
157
        description = ''
158
        feed.add_item(title, link, description)
159
        return feed
160
161
    def render_list(self, request, object_list, paginator, page_obj):
162
        feed = self.feedgenerator_class(title='', link='', description='')
163
        for obj in object_list:
164
            feed = self.add_obj(feed, obj)
165
        response = HttpResponse(mimetype=feed.mime_type)
166
        feed.write(response, 'utf-8')
167
        return response
168
169
    def element(self, request, obj):
170
        feed = self.feedgenerator_class(title='', link='', description='')
171
        feed = self.add_obj(feed, obj)
172
        response = HttpResponse(mimetype=feed.mime_type)
173
        feed.write(response, 'utf-8')
174
        return response
175
176
177
class AtomResponder(FeedResponder):
178
    feedgenerator_class = Atom1Feed
179
180
181
class RssResponder(FeedResponder):
182
    feedgenerator_class = Rss201rev2Feed
183
184
185
class SerializingResponder(BaseResponder):
186
    serializer = "YourSerializerHere"
187
    mimetype = "Serializer's MimeType"
188
    ensure_ascii = False
189
    def render_list(self, request, object_list, paginator, page_obj):
190
        if self.ensure_ascii:
191
            data = serialize(self.serializer, object_list, ensure_ascii=False)
192
        else:
193
            data = serialize(self.serializer, object_list)
194
        response = HttpResponse(data, mimetype=self.mimetype)
195
        return response
196
197
    def element(self, request, obj):
198
        """
199
        Renders single model objects to HttpResponse.
200
        """
201
        if self.ensure_ascii:
202
            data = serialize(self.serializer, [obj], ensure_ascii=False)
203
        else:
204
            data = serialize(self.serializer, [obj])
205
        response = HttpResponse(data, mimetype=self.mimetype)
206
        return response
207
208
209
class JsonResponder(SerializingResponder):
210
    serializer = 'json'
211
    mimetype = 'application/json'
212
    ensure_ascii = True
213
214
215
class XmlResponder(SerializingResponder):
216
    serializer = 'xml'
217
    mimetype = 'application/xml'
218
219
220
class YamlResponder(SerializingResponder):
221
    """
222
    The YamlResponder requires the PyYaml library to
223
    be installed for it to work properly.
224
225
        import yaml
226
227
    If the above import fails, so will the YamlResponder.
228
    """
229
    serializer = 'yaml'
230
    mimetype = 'text/yaml'

Up to file-list generic/rest_views.py:

1
1
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
2
2
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotAllowed
3
from django.template import loader, RequestContext
4
3
from django.shortcuts import render_to_response
5
from django.core.xheaders import populate_xheaders
6
from django.core.serializers import serialize
7
4
from django.newforms.models import ModelFormMetaclass, ModelForm
8
from django.utils.feedgenerator import DefaultFeed, Atom1Feed, Rss201rev2Feed
5
from responders import *
9
6
10
7
try:
11
8
    from django.views.generic.base import BaseDetailView
@@ -16,228 +13,7 @@ def django_authentication(request, **kwa
16
13
    return request.user.is_authenticated()
17
14
18
15
19
class BaseResponder(object):
20
    def __init__(self, queryset):
21
        self.queryset = queryset
22
    
23
    def get_context_vars(self, context_vars):
24
        """
25
        Returns a dictionary of context vars, override if you need more.
26
        """
27
        return context_vars
28
16
29
    def list(self, request, paginate_by, allow_empty):
30
        """
31
        Renders a list of model objects to HttpResponse.
32
        """
33
        if paginate_by:
34
            paginator = QuerySetPaginator(self.queryset, paginate_by,
35
                                          allow_empty_first_page=allow_empty)
36
            page = request.GET.get('page', 1)
37
            try:
38
                page_number = int(page)
39
            except ValueError:
40
                if page == 'last':
41
                    page_number = paginator.num_pages
42
                else:
43
                    # Page is not 'last', nor can it be converted to an int.
44
                    raise Http404
45
            try:
46
                page_obj = paginator.page(page_number)
47
            except InvalidPage:
48
                raise Http404
49
            object_list = page_obj.object_list
50
        else:
51
            object_list = self.queryset
52
            paginator = None
53
            page_obj = None
54
            if not allow_empty and len(self.queryset) == 0:
55
                raise Http404
56
        return self.render_list(request, object_list, paginator, page_obj)
57
58
    def render_list(self, request, object_list, paginator, page_obj):
59
        """
60
        Renders the specified queryset. By the time it reaches this
61
        method the queryset has already been reduced to its appropriate
62
        paginated size, and successfully passed all "should this happen"
63
        logic (in the list method), and should be rendered with minimal
64
        fuss.
65
        """
66
        raise NotImplementedError(u"render_list() must be implemented by subclass.")
67
68
    def element(self, request, obj):
69
        raise NotImplementedError(u"element() must be implemented by subclass.")
70
71
    def create_success(self, request, new_obj, post_save_redirect):
72
        """
73
        Returns an HttpResonse, generally an HttpResponse redirect. This will
74
        be the final return value of the view and will only be called if the
75
        object was saved successfuly.
76
        """
77
        # Redirect to the new object: first by trying post_save_redirect,
78
        # then by obj.get_absolute_url; fail if neither works.
79
        if post_save_redirect:
80
            return HttpResponseRedirect(post_save_redirect % new_obj.__dict__)
81
        elif hasattr(new_obj, 'get_absolute_url'):
82
            return HttpResponseRedirect(new_obj.get_absolute_url())
83
        else:
84
            raise ImproperlyConfigured("No URL to redirect to from generic create view.")
85
86
    def update_success(self, request, obj, new_obj, post_save_redirect):
87
        """
88
        Returns an HttpResonse, generally an HttpResponse redirect. This will
89
        be the final return value of the view and will only be called if the
90
        object was saved successfuly.
91
        """
92
        # Redirect to the new object: first by trying post_save_redirect,
93
        # then by obj.get_absolute_url; fail if neither works.
94
        if post_save_redirect:
95
            return HttpResponseRedirect(post_save_redirect % new_obj.__dict__)
96
        elif hasattr(new_obj, 'get_absolute_url'):
97
            return HttpResponseRedirect(new_obj.get_absolute_url())
98
        else:
99
            raise ImproperlyConfigured("No URL to redirect to from generic create view.")
100
101
    def delete_success(self, post_save_redirect):
102
        return HttpResponseRedirect(post_save_redirect)
103
    
104
105
106
class HtmlResponder(BaseResponder):
107
    """
108
    HtmlResponder renders an object or a list of objects with the Django
109
    templating system.
110
    """
111
    def render_response(self, request, template, context_vars, mimetype=None):
112
        """
113
        Returns an HttpResponse for the given request, template object,
114
        dictionary of context variables, and optional mimetype.
115
        """
116
        context = RequestContext(request, context_vars)
117
        template = template.render(context)
118
        return HttpResponse(template, mimetype=mimetype)
119
    
120
    def get_template(self, opts, target='list'):
121
        """
122
        Returns a loaded template, the template_name depends of the model name.
123
        
124
        Examples::
125
        
126
            blog/post_list.html
127
            auth/user_detail.html
128
        """
129
        template_name = "%s/%s_%s.html" % (opts.app_label, opts.object_name.lower(), target)
130
        return loader.get_template(template_name)
131
132
    def render_list(self, request, object_list, paginator, page_obj):
133
        context_vars = self.get_context_vars({
134
            'object_list': object_list,
135
            'paginator': paginator,
136
            'page_obj': page_obj
137
        })
138
        opts = self.queryset.model._meta
139
        template = self.get_template(opts)
140
        return self.render_response(request, template, context_vars)
141
142
    def element(self, request, obj):
143
        """
144
        Renders single model objects to HttpResponse.
145
        """
146
        context_vars = self.get_context_vars({'object': obj})
147
        opts = self.queryset.model._meta
148
        template = self.get_template(opts, target='detail')
149
        response = self.render_response(request, template, context_vars)
150
        populate_xheaders(request, response, self.queryset.model, getattr(obj, opts.pk.name))
151
        return response
152
153
154
class FeedResponder(BaseResponder):
155
    feedgenerator_class = DefaultFeed
156
    def add_obj(self, feed, obj):
157
        """
158
        Wrapper for feed.add_item which compute title, link and description.
159
        """
160
        title = unicode(obj)
161
        if hasattr(obj, 'get_absolute_url'):
162
            link = obj.get_absolute_url()
163
        else:
164
            raise ImproperlyConfigured(\
165
                    "get_absolute_url function  is required for model %s." % \
166
                    self.queryset.model._meta.object_name.lower())
167
        description = ''
168
        feed.add_item(title, link, description)
169
        return feed
170
171
    def render_list(self, request, object_list, paginator, page_obj):
172
        feed = self.feedgenerator_class(title='', link='', description='')
173
        for obj in object_list:
174
            feed = self.add_obj(feed, obj)
175
        response = HttpResponse(mimetype=feed.mime_type)
176
        feed.write(response, 'utf-8')
177
        return response
178
179
    def element(self, request, obj):
180
        feed = self.feedgenerator_class(title='', link='', description='')
181
        feed = self.add_obj(feed, obj)
182
        response = HttpResponse(mimetype=feed.mime_type)
183
        feed.write(response, 'utf-8')
184
        return response
185
186
187
class AtomResponder(FeedResponder):
188
    feedgenerator_class = Atom1Feed
189
190
191
class RssResponder(FeedResponder):
192
    feedgenerator_class = Rss201rev2Feed
193
194
195
class SerializingResponder(BaseResponder):
196
    serializer = "YourSerializerHere"
197
    mimetype = "Serializer's MimeType"
198
    ensure_ascii = False
199
    def render_list(self, request, object_list, paginator, page_obj):
200
        if self.ensure_ascii:
201
            data = serialize(self.serializer, object_list, ensure_ascii=False)
202
        else:
203
            data = serialize(self.serializer, object_list)
204
        response = HttpResponse(data, mimetype=self.mimetype)
205
        return response
206
207
    def element(self, request, obj):
208
        """
209
        Renders single model objects to HttpResponse.
210
        """
211
        if self.ensure_ascii:
212
            data = serialize(self.serializer, [obj], ensure_ascii=False)
213
        else:
214
            data = serialize(self.serializer, [obj])
215
        response = HttpResponse(data, mimetype=self.mimetype)
216
        return response
217
218
219
class JsonResponder(SerializingResponder):
220
    serializer = 'json'
221
    mimetype = 'application/json'
222
    ensure_ascii = True
223
224
225
class XmlResponder(SerializingResponder):
226
    serializer = 'xml'
227
    mimetype = 'application/xml'
228
229
230
class YamlResponder(SerializingResponder):
231
    """
232
    The YamlResponder requires the PyYaml library to
233
    be installed for it to work properly.
234
235
        import yaml
236
237
    If the above import fails, so will the YamlResponder.
238
    """
239
    serializer = 'yaml'
240
    mimetype = 'text/yaml'
241
17
242
18
243
19
class ModelView(BaseDetailView):