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

Changed (Δ1.9 KB):

raw changeset »

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
            obj = self.get_object(request, object_pk, slug)
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, obj, self.get_responder(format))
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, obj, self.get_responder(format))
136
            return self.update(request, subset[0], self.get_responder(format, subset))
139
137
        elif request_method == 'DELETE':
140
            return self.delete(request, obj, self.get_responder(format))
138
            return self.delete(request, subset[0], self.get_responder(format, subset))
141
139
        else:
142
140
            raise Http404
143
141
144
    def get_responder(self, format):
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()](self.get_query_set(self))
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, obj, responder):
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 obj is None:
194
        if is_list:
179
195
            return responder.list(request, self.paginate_by, self.allow_empty)
180
196
        else:
181
            return responder.element(request, obj)
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:

1
<ul>
2
{% for object in object_list %}
3
<li> {{ object.content }} </li>
4
{% endfor %}
5
</ul>

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
        User.objects.create_user('david', 'foo@bar.com', 'baz')
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
)