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 35: | e3308e2e07e4 |
| parent 34: | 15884c9d34b7 |
| branch: | default |
First implementation of feeds' responders, can't find a way to do not duplicate urls in order to catch format on lists
2 years ago
Changed (Δ2.9 KB):
raw changeset »
generic/rest_views.py (49 lines added, 5 lines removed)
tests/test_modelview/tests.py (28 lines added, 0 lines removed)
tests/urls.py (9 lines added, 5 lines removed)
Up to file-list generic/rest_views.py:
| … | … | @@ -5,6 +5,7 @@ from django.shortcuts import render_to_r |
5 |
5 |
from django.core.xheaders import populate_xheaders |
6 |
6 |
from django.core.serializers import serialize |
7 |
7 |
from django.newforms.models import ModelFormMetaclass, ModelForm |
8 |
from django.utils.feedgenerator import DefaultFeed, Atom1Feed, Rss201rev2Feed |
|
8 |
9 |
|
9 |
10 |
try: |
10 |
11 |
from django.views.generic.base import BaseDetailView |
| … | … | @@ -48,7 +49,7 @@ class BaseResponder(object): |
48 |
49 |
page_obj = None |
49 |
50 |
if not allow_empty and len(self.queryset) == 0: |
50 |
51 |
raise Http404 |
51 |
|
|
52 |
return self.render_list(request, object_list, paginator, page_obj) |
|
52 |
53 |
|
53 |
54 |
def render_list(self, request, object_list, paginator, page_obj): |
54 |
55 |
""" |
| … | … | @@ -144,7 +145,49 @@ class HtmlResponder(BaseResponder): |
144 |
145 |
response = self.render_response(request, template, context_vars) |
145 |
146 |
populate_xheaders(request, response, self.queryset.model, getattr(obj, opts.pk.name)) |
146 |
147 |
return response |
147 |
||
148 |
||
149 |
||
150 |
class FeedResponder(BaseResponder): |
|
151 |
feedgenerator_class = DefaultFeed |
|
152 |
def add_obj(self, feed, obj): |
|
153 |
""" |
|
154 |
Wrapper for feed.add_item which compute title, link and description. |
|
155 |
""" |
|
156 |
title = unicode(obj) |
|
157 |
if hasattr(obj, 'get_absolute_url'): |
|
158 |
link = obj.get_absolute_url() |
|
159 |
else: |
|
160 |
raise ImproperlyConfigured(\ |
|
161 |
"get_absolute_url function is required for model %s." % \ |
|
162 |
self.queryset.model._meta.object_name.lower()) |
|
163 |
description = '' |
|
164 |
feed.add_item(title, link, description) |
|
165 |
return feed |
|
166 |
||
167 |
def render_list(self, request, object_list, paginator, page_obj): |
|
168 |
feed = self.feedgenerator_class(title='', link='', description='') |
|
169 |
for obj in object_list: |
|
170 |
feed = self.add_obj(feed, obj) |
|
171 |
response = HttpResponse(mimetype=feed.mime_type) |
|
172 |
feed.write(response, 'utf-8') |
|
173 |
return response |
|
174 |
||
175 |
def element(self, request, obj): |
|
176 |
feed = self.feedgenerator_class(title='', link='', description='') |
|
177 |
feed = self.add_obj(feed, obj) |
|
178 |
response = HttpResponse(mimetype=feed.mime_type) |
|
179 |
feed.write(response, 'utf-8') |
|
180 |
return response |
|
181 |
||
182 |
||
183 |
class AtomResponder(FeedResponder): |
|
184 |
feedgenerator_class = Atom1Feed |
|
185 |
||
186 |
||
187 |
class RssResponder(FeedResponder): |
|
188 |
feedgenerator_class = Rss201rev2Feed |
|
189 |
||
190 |
||
148 |
191 |
class SerializingResponder(BaseResponder): |
149 |
192 |
serializer = "YourSerializerHere" |
150 |
193 |
mimetype = "Serializer's MimeType" |
| … | … | @@ -160,15 +203,18 @@ class SerializingResponder(BaseResponder |
160 |
203 |
data = serialize(self.serializer, [obj], ensure_ascii=False) |
161 |
204 |
response = HttpResponse(data, mimetype=self.mimetype) |
162 |
205 |
return response |
163 |
||
206 |
||
207 |
||
164 |
208 |
class JsonResponder(SerializingResponder): |
165 |
209 |
serializer = 'json' |
166 |
210 |
mimetype = 'application/json' |
167 |
211 |
|
212 |
||
168 |
213 |
class XmlResponder(SerializingResponder): |
169 |
214 |
serializer = 'xml' |
170 |
215 |
mimetype = 'application/xml' |
171 |
216 |
|
217 |
||
172 |
218 |
class YamlResponder(SerializingResponder): |
173 |
219 |
""" |
174 |
220 |
The YamlResponder requires the PyYaml library to |
| … | … | @@ -182,7 +228,6 @@ class YamlResponder(SerializingResponder |
182 |
228 |
mimetype = 'text/yaml' |
183 |
229 |
|
184 |
230 |
|
185 |
||
186 |
231 |
class ModelView(BaseDetailView): |
187 |
232 |
""" |
188 |
233 |
ModelView: a RESTful class-based view of your resources |
| … | … | @@ -271,7 +316,6 @@ class ModelView(BaseDetailView): |
271 |
316 |
the request. Checks whether the requested method is allowed for this |
272 |
317 |
resource. |
273 |
318 |
""" |
274 |
||
275 |
319 |
# Restrict |
276 |
320 |
request_method = request.method.upper() |
277 |
321 |
if request_method not in self.methods: |
Up to file-list tests/test_modelview/tests.py:
| … | … | @@ -81,6 +81,34 @@ class ModelViewTest(TestCase): |
81 |
81 |
self.assertEqual(response.status_code, 302) |
82 |
82 |
self.assertEqual(Article.objects.count(), 0) |
83 |
83 |
|
84 |
def test_atom_responder_read_detail(self): |
|
85 |
a = Article.objects.all()[0] |
|
86 |
response = self.client.get('/articles/%s/atom/' % a.slug) |
|
87 |
self.assertEqual(response.status_code, 200) |
|
88 |
feed_content = '</updated><entry><title>%s</title>' % a.name |
|
89 |
self.assertEqual(response.content.find(feed_content), -1) |
|
90 |
||
91 |
def test_atom_responder_read_list(self): |
|
92 |
a = Article.objects.all()[0] |
|
93 |
response = self.client.get('/articles/atom/') |
|
94 |
self.assertEqual(response.status_code, 200) |
|
95 |
feed_content = '</updated><entry><title>%s</title>' % a.name |
|
96 |
self.assertEqual(response.content.find(feed_content), -1) |
|
97 |
||
98 |
def test_rss_responder_read_detail(self): |
|
99 |
a = Article.objects.all()[0] |
|
100 |
response = self.client.get('/articles/%s/rss/' % a.slug) |
|
101 |
self.assertEqual(response.status_code, 200) |
|
102 |
feed_content = '</updated><entry><title>%s</title>' % a.name |
|
103 |
self.assertEqual(response.content.find(feed_content), -1) |
|
104 |
||
105 |
def test_rss_responder_read_list(self): |
|
106 |
a = Article.objects.all()[0] |
|
107 |
response = self.client.get('/articles/rss/') |
|
108 |
self.assertEqual(response.status_code, 200) |
|
109 |
feed_content = '</updated><entry><title>%s</title>' % a.name |
|
110 |
self.assertEqual(response.content.find(feed_content), -1) |
|
111 |
||
84 |
112 |
def test_json_responder_detail(self): |
85 |
113 |
a = Article.objects.all()[0] |
86 |
114 |
response = self.client.get('/articles/%s/json/' % a.slug) |
Up to file-list tests/urls.py:
| … | … | @@ -2,15 +2,19 @@ from django.conf.urls.defaults import * |
2 |
2 |
from test_modelview.models import Article |
3 |
3 |
from django_modelview.generic.rest_views import * |
4 |
4 |
|
5 |
||
5 |
responders = (HtmlResponder, JsonResponder, XmlResponder, AtomResponder, RssResponder) |
|
6 |
6 |
articles = ModelView(Article.objects.all(), |
7 |
responders= |
|
7 |
responders=responders, |
|
8 |
8 |
methods=('GET',)) |
9 |
9 |
rw_articles = ModelView(Article.objects.all(), |
10 |
10 |
responders=(HtmlResponder,), |
11 |
11 |
methods=('GET', 'POST', 'PUT', 'DELETE')) |
12 |
||
12 |
||
13 |
formats = '(?P<format>(html|json|xml|yaml|atom|rss))?/?' |
|
14 |
slug = '(?P<slug>[-\w]+)?/?' |
|
15 |
||
13 |
16 |
urlpatterns = patterns('', |
14 |
('^articles/(?P<slug>[-\w]+)?/?(?P<format>(html|json|xml|yaml))?/?$', articles), |
|
15 |
('^rw-articles/(?P<slug>[-\w]+)?/?$', rw_articles), |
|
17 |
('^articles/%(formats)s$' % locals(), articles), |
|
18 |
('^articles/%(slug)s%(formats)s$' % locals(), articles), |
|
19 |
('^rw-articles/%(slug)s$' % locals(), rw_articles), |
|
16 |
20 |
) |
