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
David Larlet / david
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
        self.render_list(request, object_list, paginator, page_obj)
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=(HtmlResponder,JsonResponder,XmlResponder),
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
)