64 self.load_middleware() |
64 self.load_middleware() |
65 |
65 |
66 signals.request_started.send(sender=self.__class__) |
66 signals.request_started.send(sender=self.__class__) |
67 try: |
67 try: |
68 request = WSGIRequest(environ) |
68 request = WSGIRequest(environ) |
|
69 # sneaky little hack so that we can easily get round |
|
70 # CsrfViewMiddleware. This makes life easier, and is probably |
|
71 # required for backwards compatibility with external tests against |
|
72 # admin views. |
|
73 request._dont_enforce_csrf_checks = True |
69 response = self.get_response(request) |
74 response = self.get_response(request) |
70 |
75 |
71 # Apply response middleware. |
76 # Apply response middleware. |
72 for middleware_method in self._response_middleware: |
77 for middleware_method in self._response_middleware: |
73 response = middleware_method(request, response) |
78 response = middleware_method(request, response) |
214 |
219 |
215 # Curry a data dictionary into an instance of the template renderer |
220 # Curry a data dictionary into an instance of the template renderer |
216 # callback function. |
221 # callback function. |
217 data = {} |
222 data = {} |
218 on_template_render = curry(store_rendered_templates, data) |
223 on_template_render = curry(store_rendered_templates, data) |
219 signals.template_rendered.connect(on_template_render) |
224 signals.template_rendered.connect(on_template_render, dispatch_uid="template-render") |
220 |
|
221 # Capture exceptions created by the handler. |
225 # Capture exceptions created by the handler. |
222 got_request_exception.connect(self.store_exc_info) |
226 got_request_exception.connect(self.store_exc_info, dispatch_uid="request-exception") |
223 |
|
224 try: |
227 try: |
225 response = self.handler(environ) |
228 |
226 except TemplateDoesNotExist, e: |
229 try: |
227 # If the view raises an exception, Django will attempt to show |
230 response = self.handler(environ) |
228 # the 500.html template. If that template is not available, |
231 except TemplateDoesNotExist, e: |
229 # we should ignore the error in favor of re-raising the |
232 # If the view raises an exception, Django will attempt to show |
230 # underlying exception that caused the 500 error. Any other |
233 # the 500.html template. If that template is not available, |
231 # template found to be missing during view error handling |
234 # we should ignore the error in favor of re-raising the |
232 # should be reported as-is. |
235 # underlying exception that caused the 500 error. Any other |
233 if e.args != ('500.html',): |
236 # template found to be missing during view error handling |
234 raise |
237 # should be reported as-is. |
235 |
238 if e.args != ('500.html',): |
236 # Look for a signalled exception, clear the current context |
239 raise |
237 # exception data, then re-raise the signalled exception. |
240 |
238 # Also make sure that the signalled exception is cleared from |
241 # Look for a signalled exception, clear the current context |
239 # the local cache! |
242 # exception data, then re-raise the signalled exception. |
240 if self.exc_info: |
243 # Also make sure that the signalled exception is cleared from |
241 exc_info = self.exc_info |
244 # the local cache! |
242 self.exc_info = None |
245 if self.exc_info: |
243 raise exc_info[1], None, exc_info[2] |
246 exc_info = self.exc_info |
244 |
247 self.exc_info = None |
245 # Save the client and request that stimulated the response. |
248 raise exc_info[1], None, exc_info[2] |
246 response.client = self |
249 |
247 response.request = request |
250 # Save the client and request that stimulated the response. |
248 |
251 response.client = self |
249 # Add any rendered template detail to the response. |
252 response.request = request |
250 # If there was only one template rendered (the most likely case), |
253 |
251 # flatten the list to a single element. |
254 # Add any rendered template detail to the response. |
252 for detail in ('template', 'context'): |
255 # If there was only one template rendered (the most likely case), |
253 if data.get(detail): |
256 # flatten the list to a single element. |
254 if len(data[detail]) == 1: |
257 for detail in ('template', 'context'): |
255 setattr(response, detail, data[detail][0]); |
258 if data.get(detail): |
|
259 if len(data[detail]) == 1: |
|
260 setattr(response, detail, data[detail][0]); |
|
261 else: |
|
262 setattr(response, detail, data[detail]) |
256 else: |
263 else: |
257 setattr(response, detail, data[detail]) |
264 setattr(response, detail, None) |
258 else: |
265 |
259 setattr(response, detail, None) |
266 # Update persistent cookie data. |
260 |
267 if response.cookies: |
261 # Update persistent cookie data. |
268 self.cookies.update(response.cookies) |
262 if response.cookies: |
269 |
263 self.cookies.update(response.cookies) |
270 return response |
264 |
271 finally: |
265 return response |
272 signals.template_rendered.disconnect(dispatch_uid="template-render") |
|
273 got_request_exception.disconnect(dispatch_uid="request-exception") |
|
274 |
266 |
275 |
267 def get(self, path, data={}, follow=False, **extra): |
276 def get(self, path, data={}, follow=False, **extra): |
268 """ |
277 """ |
269 Requests a response from the server using GET. |
278 Requests a response from the server using GET. |
270 """ |
279 """ |
360 if content_type is MULTIPART_CONTENT: |
369 if content_type is MULTIPART_CONTENT: |
361 post_data = encode_multipart(BOUNDARY, data) |
370 post_data = encode_multipart(BOUNDARY, data) |
362 else: |
371 else: |
363 post_data = data |
372 post_data = data |
364 |
373 |
|
374 # Make `data` into a querystring only if it's not already a string. If |
|
375 # it is a string, we'll assume that the caller has already encoded it. |
|
376 query_string = None |
|
377 if not isinstance(data, basestring): |
|
378 query_string = urlencode(data, doseq=True) |
|
379 |
365 parsed = urlparse(path) |
380 parsed = urlparse(path) |
366 r = { |
381 r = { |
367 'CONTENT_LENGTH': len(post_data), |
382 'CONTENT_LENGTH': len(post_data), |
368 'CONTENT_TYPE': content_type, |
383 'CONTENT_TYPE': content_type, |
369 'PATH_INFO': urllib.unquote(parsed[2]), |
384 'PATH_INFO': urllib.unquote(parsed[2]), |
370 'QUERY_STRING': urlencode(data, doseq=True) or parsed[4], |
385 'QUERY_STRING': query_string or parsed[4], |
371 'REQUEST_METHOD': 'PUT', |
386 'REQUEST_METHOD': 'PUT', |
372 'wsgi.input': FakePayload(post_data), |
387 'wsgi.input': FakePayload(post_data), |
373 } |
388 } |
374 r.update(extra) |
389 r.update(extra) |
375 |
390 |
457 scheme, netloc, path, query, fragment = urlsplit(url) |
472 scheme, netloc, path, query, fragment = urlsplit(url) |
458 |
473 |
459 redirect_chain = response.redirect_chain |
474 redirect_chain = response.redirect_chain |
460 redirect_chain.append((url, response.status_code)) |
475 redirect_chain.append((url, response.status_code)) |
461 |
476 |
|
477 extra = {} |
|
478 if scheme: |
|
479 extra['wsgi.url_scheme'] = scheme |
|
480 |
462 # The test client doesn't handle external links, |
481 # The test client doesn't handle external links, |
463 # but since the situation is simulated in test_client, |
482 # but since the situation is simulated in test_client, |
464 # we fake things here by ignoring the netloc portion of the |
483 # we fake things here by ignoring the netloc portion of the |
465 # redirected URL. |
484 # redirected URL. |
466 response = self.get(path, QueryDict(query), follow=False) |
485 response = self.get(path, QueryDict(query), follow=False, **extra) |
467 response.redirect_chain = redirect_chain |
486 response.redirect_chain = redirect_chain |
468 |
487 |
469 # Prevent loops |
488 # Prevent loops |
470 if response.redirect_chain[-1] in response.redirect_chain[0:-1]: |
489 if response.redirect_chain[-1] in response.redirect_chain[0:-1]: |
471 break |
490 break |