30 |
30 |
|
31 |
31 |
|
32 |
32 |
class to_json(object):
|
33 |
|
"""
|
34 |
|
Wrap view functions to render python native and custom
|
35 |
|
objects to json
|
36 |
|
|
37 |
|
>>> from django.test.client import RequestFactory
|
38 |
|
>>> requests = RequestFactory()
|
39 |
|
|
40 |
|
Simple wrap returning data into json
|
41 |
|
|
42 |
|
>>> @to_json('plain')
|
43 |
|
... def hello(request):
|
44 |
|
... return dict(hello='world')
|
45 |
|
|
46 |
|
>>> resp = hello(requests.get('/hello/'))
|
47 |
|
>>> print resp.status_code
|
48 |
|
200
|
49 |
|
>>> print resp.content
|
50 |
|
{"hello": "world"}
|
51 |
|
|
52 |
|
Result can be wraped in some api manier
|
53 |
|
|
54 |
|
>>> @to_json('api')
|
55 |
|
... def goodbye(request):
|
56 |
|
... return dict(good='bye')
|
57 |
|
>>> resp = goodbye(requests.get('/goodbye', {'debug': 1}))
|
58 |
|
>>> print resp.status_code
|
59 |
|
200
|
60 |
|
>>> print resp.content
|
61 |
|
{
|
62 |
|
"data": {
|
63 |
|
"good": "bye"
|
64 |
|
},
|
65 |
|
"err": 0
|
66 |
|
}
|
67 |
|
|
68 |
|
Automaticaly error handling
|
69 |
|
|
70 |
|
>>> @to_json('api')
|
71 |
|
... def error(request):
|
72 |
|
... raise Exception('Wooot!??')
|
73 |
|
|
74 |
|
>>> resp = error(requests.get('/error', {'debug': 1}))
|
75 |
|
>>> print resp.status_code
|
76 |
|
500
|
77 |
|
>>> print resp.content # doctest: +NORMALIZE_WHITESPACE
|
78 |
|
{
|
79 |
|
"err_class": "Exception",
|
80 |
|
"err_desc": "Wooot!??",
|
81 |
|
"data": null,
|
82 |
|
"err": 1
|
83 |
|
}
|
84 |
|
|
85 |
|
>>> from django.core.exceptions import ObjectDoesNotExist
|
86 |
|
>>> @to_json('api')
|
87 |
|
... def error_404(request):
|
88 |
|
... raise ObjectDoesNotExist('Not found')
|
89 |
|
|
90 |
|
>>> resp = error_404(requests.get('/error', {'debug': 1}))
|
91 |
|
>>> print resp.status_code
|
92 |
|
404
|
93 |
|
>>> print resp.content # doctest: +NORMALIZE_WHITESPACE
|
94 |
|
{
|
95 |
|
"err_class": "django.core.exceptions.ObjectDoesNotExist",
|
96 |
|
"err_desc": "Not found",
|
97 |
|
"data": null,
|
98 |
|
"err": 1
|
99 |
|
}
|
100 |
|
|
101 |
|
|
102 |
|
You can serialize not only pure python data types.
|
103 |
|
Implement `serialize` method on toplevel object or
|
104 |
|
each element of toplevel array.
|
105 |
|
|
106 |
|
>>> class User(object):
|
107 |
|
... def __init__(self, name, age):
|
108 |
|
... self.name = name
|
109 |
|
... self.age = age
|
110 |
|
...
|
111 |
|
... def serialize(self, request):
|
112 |
|
... if request.GET.get('with_age', False):
|
113 |
|
... return dict(name=self.name, age=self.age)
|
114 |
|
... else:
|
115 |
|
... return dict(name=self.name)
|
116 |
|
|
117 |
|
>>> @to_json('objects')
|
118 |
|
... def users(request):
|
119 |
|
... return [User('Bob', 10), User('Anna', 12)]
|
120 |
|
|
121 |
|
>>> resp = users(requests.get('users', { 'debug': 1 }))
|
122 |
|
>>> print resp.status_code
|
123 |
|
200
|
124 |
|
>>> print resp.content # doctest: +NORMALIZE_WHITESPACE
|
125 |
|
{
|
126 |
|
"data": [
|
127 |
|
{
|
128 |
|
"name": "Bob"
|
129 |
|
},
|
130 |
|
{
|
131 |
|
"name": "Anna"
|
132 |
|
}
|
133 |
|
],
|
134 |
|
"err": 0
|
135 |
|
}
|
136 |
|
|
137 |
|
You can pass extra args for serialization:
|
138 |
|
|
139 |
|
>>> resp = users(requests.get('users',
|
140 |
|
... { 'debug':1, 'with_age':1 }))
|
141 |
|
>>> print resp.status_code
|
142 |
|
200
|
143 |
|
>>> print resp.content # doctest: +NORMALIZE_WHITESPACE
|
144 |
|
{
|
145 |
|
"data": [
|
146 |
|
{
|
147 |
|
"age": 10,
|
148 |
|
"name": "Bob"
|
149 |
|
},
|
150 |
|
{
|
151 |
|
"age": 12,
|
152 |
|
"name": "Anna"
|
153 |
|
}
|
154 |
|
],
|
155 |
|
"err": 0
|
156 |
|
}
|
157 |
|
|
158 |
|
It is easy to use jsonp, just pass format=jsonp
|
159 |
|
|
160 |
|
>>> resp = users(requests.get('users',
|
161 |
|
... { 'debug':1, 'format': 'jsonp' }))
|
162 |
|
>>> print resp.status_code
|
163 |
|
200
|
164 |
|
>>> print resp.content # doctest: +NORMALIZE_WHITESPACE
|
165 |
|
callback({
|
166 |
|
"data": [
|
167 |
|
{
|
168 |
|
"name": "Bob"
|
169 |
|
},
|
170 |
|
{
|
171 |
|
"name": "Anna"
|
172 |
|
}
|
173 |
|
],
|
174 |
|
"err": 0
|
175 |
|
});
|
176 |
|
|
177 |
|
You can override the name of callback method using
|
178 |
|
JSONRESPONSE_CALLBACK_NAME option or query arg callback=another_callback
|
179 |
|
(in this case, format=jsonp if not specified)
|
180 |
|
|
181 |
|
>>> resp = users(requests.get('users',
|
182 |
|
... { 'debug':1, 'callback': 'my_callback' }))
|
183 |
|
>>> print resp.status_code
|
184 |
|
200
|
185 |
|
>>> print resp.content # doctest: +NORMALIZE_WHITESPACE
|
186 |
|
my_callback({
|
187 |
|
"data": [
|
188 |
|
{
|
189 |
|
"name": "Bob"
|
190 |
|
},
|
191 |
|
{
|
192 |
|
"name": "Anna"
|
193 |
|
}
|
194 |
|
],
|
195 |
|
"err": 0
|
196 |
|
});
|
197 |
|
|
198 |
|
You can pass raise=1 to raise exceptions in debug purposes
|
199 |
|
instead of passing info to json response
|
200 |
|
|
201 |
|
>>> @to_json('api')
|
202 |
|
... def error(request):
|
203 |
|
... raise Exception('Wooot!??')
|
204 |
|
|
205 |
|
>>> resp = error(requests.get('/error',
|
206 |
|
... {'debug': 1, 'raise': 1}))
|
207 |
|
Traceback (most recent call last):
|
208 |
|
Exception: Wooot!??
|
209 |
|
|
210 |
|
You can wraps both methods and functions
|
211 |
|
|
212 |
|
>>> class View(object):
|
213 |
|
... @to_json('plain')
|
214 |
|
... def render(self, request):
|
215 |
|
... return dict(data='ok')
|
216 |
|
... @to_json('api')
|
217 |
|
... def render_api(self, request):
|
218 |
|
... return dict(data='ok')
|
219 |
|
|
220 |
|
|
221 |
|
>>> view = View()
|
222 |
|
>>> resp = view.render(requests.get('/render'))
|
223 |
|
>>> print resp.status_code
|
224 |
|
200
|
225 |
|
>>> print resp.content # doctest: +NORMALIZE_WHITESPACE
|
226 |
|
{"data": "ok"}
|
227 |
|
|
228 |
|
Try it one more
|
229 |
|
|
230 |
|
>>> resp = view.render(requests.get('/render'))
|
231 |
|
>>> print resp.status_code
|
232 |
|
200
|
233 |
|
>>> print resp.content # doctest: +NORMALIZE_WHITESPACE
|
234 |
|
{"data": "ok"}
|
235 |
|
|
236 |
|
Try it one more with api
|
237 |
|
|
238 |
|
>>> resp = view.render_api(requests.get('/render'))
|
239 |
|
>>> print resp.status_code
|
240 |
|
200
|
241 |
|
>>> print resp.content # doctest: +NORMALIZE_WHITESPACE
|
242 |
|
{"data": {"data": "ok"}, "err": 0}
|
243 |
|
|
244 |
|
|
245 |
|
You can pass custom kwargs to json.dumps,
|
246 |
|
just give them to constructor
|
247 |
|
|
248 |
|
>>> @to_json('plain', separators=(', ', ': '))
|
249 |
|
... def custom_kwargs(request):
|
250 |
|
... return ['a', { 'b': 1 }]
|
251 |
|
>>> resp = custom_kwargs(requests.get('/render'))
|
252 |
|
>>> print resp.status_code
|
253 |
|
200
|
254 |
|
>>> print resp.content
|
255 |
|
["a", {"b": 1}]
|
256 |
|
"""
|
257 |
33 |
def __init__(self, serializer_type, error_code=500, wrap_response=True, **kwargs):
|
258 |
34 |
"""
|
259 |
35 |
serializer_types:
|
260 |
|
-
|