david / django-modelviews
Backup of an old repository with useful ideas. Initial goal: integrating REST to django admin (class-based views).
$ hg clone http://code.welldev.org/django-modelviews
| commit 41: | 1485fb2f6599 |
| parent 40: | 08ef53bf9dda |
| branch: | default |
2 years ago
Changed (Δ1.9 KB):
generic/rest_views.py (30 lines added, 14 lines removed)
tests/templates/test_modelview/comment_list.html (5 lines added, 0 lines removed)
tests/test_modelview/models.py (5 lines added, 0 lines removed)
tests/test_modelview/tests.py (17 lines added, 2 lines removed)
tests/urls.py (6 lines added, 1 lines removed)
Up to file-list generic/rest_views.py:
| … | … | @@ -123,25 +123,41 @@ class ModelView(BaseDetailView): |
123 |
123 |
if format is None: |
124 |
124 |
format = 'html' |
125 |
125 |
|
126 |
# If we didn't get object_pk or slug, assume this is an add view. |
|
127 |
if object_pk is None and slug is None: |
|
128 |
obj = None |
|
129 |
else: |
|
130 |
|
|
126 |
# Filter initial queryset given request arguments. |
|
127 |
subset = self.get_subset(request, object_pk, slug, **kwargs) |
|
131 |
128 |
|
132 |
129 |
# Dispatch |
133 |
130 |
if request_method == 'GET': |
134 |
return self.read(request, |
|
131 |
return self.read(request, subset, self.get_responder(format, subset), |
|
132 |
is_list=object_pk is None and slug is None) |
|
135 |
133 |
elif request_method == 'POST': |
136 |
return self.create(request, self.get_responder(format |
|
134 |
return self.create(request, self.get_responder(format, subset)) |
|
137 |
135 |
elif request_method == 'PUT': |
138 |
return self.update(request, |
|
136 |
return self.update(request, subset[0], self.get_responder(format, subset)) |
|
139 |
137 |
elif request_method == 'DELETE': |
140 |
return self.delete(request, |
|
138 |
return self.delete(request, subset[0], self.get_responder(format, subset)) |
|
141 |
139 |
else: |
142 |
140 |
raise Http404 |
143 |
141 |
|
144 |
def get_ |
|
142 |
def get_subset(self, request, object_pk=None, slug=None, **kwargs): |
|
143 |
""" |
|
144 |
Returns the filtered queryset from arguments. |
|
145 |
""" |
|
146 |
# Verify if lookup arguments exist |
|
147 |
if 'lookup_kwargs' in kwargs: |
|
148 |
lookup_kwargs = kwargs['lookup_kwargs'] |
|
149 |
for k, v in lookup_kwargs.items(): |
|
150 |
lookup_kwargs[k] = v % kwargs |
|
151 |
else: |
|
152 |
lookup_kwargs = {} |
|
153 |
||
154 |
if object_pk: |
|
155 |
lookup_kwargs['pk'] = object_pk |
|
156 |
elif slug and self.slug_field: |
|
157 |
lookup_kwargs[self.slug_field] = slug |
|
158 |
return self.get_query_set(request).filter(**lookup_kwargs) |
|
159 |
||
160 |
def get_responder(self, format, subset): |
|
145 |
161 |
""" |
146 |
162 |
Returns a ``Responder`` instance given the format. |
147 |
163 |
""" |
| … | … | @@ -149,7 +165,7 @@ class ModelView(BaseDetailView): |
149 |
165 |
# get_query_set requires a request parameter, but doesn't |
150 |
166 |
# do anything with the parameter (presumably a subclass |
151 |
167 |
# might. Passing self is an arbitrary decision. |
152 |
return self.responders['%sResponder' % format.title()](s |
|
168 |
return self.responders['%sResponder' % format.title()](subset) |
|
153 |
169 |
except KeyError: |
154 |
170 |
raise ImproperlyConfigured("%s responder doesn't exist." % '%sResponder' % format.title()) |
155 |
171 |
|
| … | … | @@ -171,14 +187,14 @@ class ModelView(BaseDetailView): |
171 |
187 |
""" |
172 |
188 |
return form.save() |
173 |
189 |
|
174 |
def read(self, request, |
|
190 |
def read(self, request, subset, responder, is_list): |
|
175 |
191 |
""" |
176 |
192 |
Returns a rendered list or element whether ``obj`` exists, idempotent. |
177 |
193 |
""" |
178 |
if |
|
194 |
if is_list: |
|
179 |
195 |
return responder.list(request, self.paginate_by, self.allow_empty) |
180 |
196 |
else: |
181 |
return responder.element(request, |
|
197 |
return responder.element(request, subset[0]) |
|
182 |
198 |
|
183 |
199 |
def create(self, request, responder): |
184 |
200 |
""" |
Up to file-list tests/templates/test_modelview/comment_list.html:
Up to file-list tests/test_modelview/models.py:
1 |
1 |
from django.db import models |
2 |
from django.contrib.auth.models import User |
|
2 |
3 |
|
3 |
4 |
class Article(models.Model): |
4 |
5 |
name = models.CharField(max_length=50) |
| … | … | @@ -9,3 +10,7 @@ class Article(models.Model): |
9 |
10 |
def get_absolute_url(self): |
10 |
11 |
# TODO: find a better way to handle that |
11 |
12 |
return '/rw-articles/%s/' % self.slug |
13 |
||
14 |
class Comment(models.Model): |
|
15 |
content = models.CharField(max_length=50) |
|
16 |
user = models.ForeignKey(User) |
Up to file-list tests/test_modelview/tests.py:
1 |
1 |
from django.test import TestCase |
2 |
from models import Article |
|
2 |
from models import Article, Comment |
|
3 |
3 |
from django.utils import simplejson |
4 |
4 |
from django.contrib.auth.models import User |
5 |
5 |
from xml.dom.minidom import parseString |
| … | … | @@ -20,7 +20,10 @@ class ModelViewTest(TestCase): |
20 |
20 |
Article.objects.create(name="My Story", |
21 |
21 |
slug="my-story", |
22 |
22 |
body="My thrilling story!") |
23 |
|
|
23 |
david = User.objects.create_user('david', 'foo@example.com', 'baz') |
|
24 |
will = User.objects.create_user('will', 'bar@example.com', 'baz') |
|
25 |
Comment.objects.create(content="David comment", user=david) |
|
26 |
Comment.objects.create(content="Will comment", user=will) |
|
24 |
27 |
|
25 |
28 |
def test_restricting_exposed_methods(self): |
26 |
29 |
""" |
| … | … | @@ -199,3 +202,15 @@ class ModelViewTest(TestCase): |
199 |
202 |
self.assertEqual(len(data), Article.objects.count()) |
200 |
203 |
except ImportError: |
201 |
204 |
pass |
205 |
||
206 |
||
207 |
def test_nested_resource(self): |
|
208 |
david = User.objects.all()[0] |
|
209 |
david_comment = Comment.objects.all()[0] |
|
210 |
will_comment = Comment.objects.all()[1] |
|
211 |
response = self.client.get('/users/%s/comments/' % david.username) |
|
212 |
self.assertEqual(response.status_code, 200) |
|
213 |
self.assertTemplateUsed(response, 'test_modelview/comment_list.html') |
|
214 |
self.assertNotEqual(response.content.find(david_comment.content), -1) |
|
215 |
self.assertEqual(response.content.find(will_comment.content), -1) |
|
216 |
Up to file-list tests/urls.py:
1 |
1 |
from django.conf.urls.defaults import * |
2 |
from test_modelview.models import Article |
|
2 |
from test_modelview.models import Article, Comment |
|
3 |
3 |
from django_modelview.generic.rest_views import * |
4 |
4 |
|
5 |
5 |
responders = (HtmlResponder, JsonResponder, XmlResponder, |
| … | … | @@ -13,6 +13,9 @@ rw_articles = ModelView(Article.objects. |
13 |
13 |
auth_articles = ModelView(Article.objects.all(), |
14 |
14 |
responders=(HtmlResponder,), |
15 |
15 |
methods={'GET': django_authentication}) |
16 |
comments = ModelView(Comment.objects.all(), |
|
17 |
responders=(HtmlResponder,), |
|
18 |
methods=('GET',)) |
|
16 |
19 |
|
17 |
20 |
formats = '(?P<format>(html|json|xml|yaml|atom|rss))?/?' |
18 |
21 |
slug = '(?P<slug>[-\w]+)?/?' |
| … | … | @@ -22,4 +25,6 @@ urlpatterns = patterns('', |
22 |
25 |
('^articles/%(slug)s%(formats)s$' % locals(), articles), |
23 |
26 |
('^rw-articles/%(slug)s$' % locals(), rw_articles), |
24 |
27 |
('^auth-articles/%(slug)s$' % locals(), auth_articles), |
28 |
('^users/(?P<username>[-\w]+)/comments/%(slug)s$' % locals(), comments, |
|
29 |
{'lookup_kwargs': {'user__username__exact': '%(username)s'}}), |
|
25 |
30 |
) |
