root / ui / userdata / rest.py @ c72a830d
History | View | Annotate | Download (6.8 kB)
1 |
from django import http |
---|---|
2 |
from django.template import RequestContext, loader |
3 |
from django.utils import simplejson as json |
4 |
from django.core import serializers |
5 |
from django.core.urlresolvers import reverse |
6 |
|
7 |
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS |
8 |
|
9 |
# base view class
|
10 |
# https://github.com/bfirsh/django-class-based-views/blob/master/class_based_views/base.py
|
11 |
class View(object): |
12 |
"""
|
13 |
Intentionally simple parent class for all views. Only implements
|
14 |
dispatch-by-method and simple sanity checking.
|
15 |
"""
|
16 |
|
17 |
method_names = ['GET', 'POST', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE'] |
18 |
|
19 |
def __init__(self, *args, **kwargs): |
20 |
"""
|
21 |
Constructor. Called in the URLconf; can contain helpful extra
|
22 |
keyword arguments, and other things.
|
23 |
"""
|
24 |
# Go through keyword arguments, and either save their values to our
|
25 |
# instance, or raise an error.
|
26 |
for key, value in kwargs.items(): |
27 |
if key in self.method_names: |
28 |
raise TypeError(u"You tried to pass in the %s method name as a " |
29 |
u"keyword argument to %s(). Don't do that."
|
30 |
% (key, self.__class__.__name__))
|
31 |
if hasattr(self, key): |
32 |
setattr(self, key, value) |
33 |
else:
|
34 |
raise TypeError(u"%s() received an invalid keyword %r" % ( |
35 |
self.__class__.__name__,
|
36 |
key, |
37 |
)) |
38 |
|
39 |
@classmethod
|
40 |
def as_view(cls, *initargs, **initkwargs): |
41 |
"""
|
42 |
Main entry point for a request-response process.
|
43 |
"""
|
44 |
def view(request, *args, **kwargs): |
45 |
self = cls(*initargs, **initkwargs)
|
46 |
return self.dispatch(request, *args, **kwargs) |
47 |
return view
|
48 |
|
49 |
def dispatch(self, request, *args, **kwargs): |
50 |
# Try to dispatch to the right method for that; if it doesn't exist,
|
51 |
# raise a big error.
|
52 |
if hasattr(self, request.method.upper()): |
53 |
self.request = request
|
54 |
self.args = args
|
55 |
self.kwargs = kwargs
|
56 |
data = request.raw_post_data |
57 |
|
58 |
if request.method.upper() in ['POST', 'PUT']: |
59 |
# Expect json data
|
60 |
if request.META.get('CONTENT_TYPE').startswith('application/json'): |
61 |
try:
|
62 |
data = json.loads(data) |
63 |
except ValueError: |
64 |
raise http.HttpResponseServerError('Invalid JSON data.') |
65 |
else:
|
66 |
raise http.HttpResponseServerError('Unsupported Content-Type.') |
67 |
try:
|
68 |
return getattr(self, request.method.upper())(request, data, *args, **kwargs) |
69 |
except ValidationError, e:
|
70 |
# specific response for validation errors
|
71 |
return http.HttpResponseServerError(json.dumps({'errors': |
72 |
e.message_dict, 'non_field_key':
|
73 |
NON_FIELD_ERRORS })) |
74 |
|
75 |
else:
|
76 |
allowed_methods = [m for m in self.method_names if hasattr(self, m)] |
77 |
return http.HttpResponseNotAllowed(allowed_methods)
|
78 |
|
79 |
class JSONRestView(View): |
80 |
"""
|
81 |
Class that provides helpers to produce a json response
|
82 |
"""
|
83 |
|
84 |
url_name = None
|
85 |
def __init__(self, url_name, *args, **kwargs): |
86 |
self.url_name = url_name
|
87 |
return super(JSONRestView, self).__init__(*args, **kwargs) |
88 |
|
89 |
def update_instance(self, i, data, exclude_fields=[]): |
90 |
update_keys = data.keys() |
91 |
for field in i._meta.get_all_field_names(): |
92 |
if field in update_keys and (field not in exclude_fields): |
93 |
i.__setattr__(field, data[field]) |
94 |
|
95 |
return i
|
96 |
|
97 |
def instance_to_dict(self, i, exclude_fields=[]): |
98 |
"""
|
99 |
Convert model instance to python dict
|
100 |
"""
|
101 |
d = {} |
102 |
d['uri'] = reverse(self.url_name, kwargs={'id': i.pk}) |
103 |
|
104 |
for field in i._meta.get_all_field_names(): |
105 |
if field in exclude_fields: |
106 |
continue
|
107 |
|
108 |
d[field] = i.__getattribute__(field) |
109 |
return d
|
110 |
|
111 |
def qs_to_dict_iter(self, qs, exclude_fields=[]): |
112 |
"""
|
113 |
Convert queryset to an iterator of model instances dicts
|
114 |
"""
|
115 |
for i in qs: |
116 |
yield self.instance_to_dict(i, exclude_fields) |
117 |
|
118 |
def json_response(self, data): |
119 |
return http.HttpResponse(json.dumps(data), mimetype="application/json") |
120 |
|
121 |
class ResourceView(JSONRestView): |
122 |
method_names = ['GET', 'POST', 'PUT', 'DELETE'] |
123 |
|
124 |
model = None
|
125 |
exclude_fields = [] |
126 |
|
127 |
def queryset(self): |
128 |
return self.model.objects.all() |
129 |
|
130 |
def instance(self): |
131 |
"""
|
132 |
Retrieve selected instance based on url parameter
|
133 |
|
134 |
id parameter should be set in urlpatterns expression
|
135 |
"""
|
136 |
try:
|
137 |
return self.queryset().get(pk=self.kwargs.get("id")) |
138 |
except self.model.DoesNotExist: |
139 |
raise http.Http404
|
140 |
|
141 |
def GET(self, request, data, *args, **kwargs): |
142 |
return self.json_response(self.instance_to_dict(self.instance(), |
143 |
self.exclude_fields))
|
144 |
|
145 |
def PUT(self, request, data, *args, **kwargs): |
146 |
instance = self.instance()
|
147 |
self.update_instance(instance, data, self.exclude_fields) |
148 |
instance.full_clean() |
149 |
instance.save() |
150 |
return self.GET(request, data, *args, **kwargs) |
151 |
|
152 |
def DELETE(self, request, data, *args, **kwargs): |
153 |
self.instance().delete()
|
154 |
return self.json_response("") |
155 |
|
156 |
|
157 |
class CollectionView(JSONRestView): |
158 |
method_names = ['GET', 'POST'] |
159 |
|
160 |
model = None
|
161 |
exclude_fields = [] |
162 |
|
163 |
def queryset(self): |
164 |
return self.model.objects.all() |
165 |
|
166 |
def GET(self, request, data, *args, **kwargs): |
167 |
return self.json_response(list(self.qs_to_dict_iter(self.queryset(), |
168 |
self.exclude_fields)))
|
169 |
|
170 |
def POST(self, request, data, *args, **kwargs): |
171 |
instance = self.model()
|
172 |
self.update_instance(instance, data, self.exclude_fields) |
173 |
instance.full_clean() |
174 |
instance.save() |
175 |
return self.json_response(self.instance_to_dict(instance, |
176 |
self.exclude_fields))
|
177 |
|
178 |
class UserResourceView(ResourceView): |
179 |
"""
|
180 |
Filter resource queryset for request user entries
|
181 |
"""
|
182 |
def queryset(self): |
183 |
return super(UserResourceView, |
184 |
self).queryset().filter(user=self.request.user) |
185 |
|
186 |
class UserCollectionView(CollectionView): |
187 |
"""
|
188 |
Filter collection queryset for request user entries
|
189 |
"""
|
190 |
def queryset(self): |
191 |
return super(UserCollectionView, self).queryset().filter(user=self.request.user) |
192 |
|
193 |
def POST(self, request, data, *args, **kwargs): |
194 |
instance = self.model()
|
195 |
self.update_instance(instance, data, self.exclude_fields) |
196 |
instance.user = request.user |
197 |
instance.full_clean() |
198 |
instance.save() |
199 |
return self.json_response(self.instance_to_dict(instance, |
200 |
self.exclude_fields))
|
201 |
|