Custom Errors Documentation
- DocString'ed pecan.middleware.errordocument.py - Wrote a Custom Errors Cookbook - Fixed a bug in base config.py scaffold
This commit is contained in:
@@ -2,4 +2,115 @@
|
||||
|
||||
Custom Error Documents
|
||||
======================
|
||||
TODO
|
||||
In this article we will configure a Pecan application to display a custom
|
||||
Error page whenever the server returns ``404 Page not Found`` status.
|
||||
|
||||
This article assumes that you have already created a test application as
|
||||
described in :ref:`quick_start`
|
||||
|
||||
.. note::
|
||||
While this example focuses on the ``HTTP 404 status`` message, the same
|
||||
technique may be applied to define custom actions for any of the ``HTTP``
|
||||
status response codes in the 400 and 500 range. You are well advised to use
|
||||
this power judiciously.
|
||||
|
||||
.. _overview:
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Pecan makes it simple to customize error documents in two simple steps:
|
||||
|
||||
* :ref:`configure` of the HTTP status messages you want to handle
|
||||
in your application's config.py
|
||||
* :ref:`controllers` to handle the status messages you have configured
|
||||
|
||||
.. _configure:
|
||||
|
||||
Configure Routing
|
||||
-----------------
|
||||
Let's configure our application *test_project* to route the ``HTTP 404``
|
||||
(page not found) messages to our custom built controller.
|
||||
|
||||
First, we tweak test_project/config.py::
|
||||
|
||||
# Pecan Application Configurations
|
||||
app = {
|
||||
'root' : 'test_project.controllers.root.RootController',
|
||||
'modules' : ['test_project'],
|
||||
'static_root' : '%(confdir)s/public',
|
||||
'template_path' : '%(confdir)s/test_project/templates',
|
||||
'reload' : True,
|
||||
'debug' : True,
|
||||
|
||||
## modify the 'errors' element to direct HTTP status codes to your
|
||||
## own controller.
|
||||
'errors' : {
|
||||
#404 : '/error/404',
|
||||
404 : '/notfound',
|
||||
'__force_dict__' : True
|
||||
}
|
||||
}
|
||||
|
||||
Instead of the default error page, Pecan will now route 404 messages to our
|
||||
very own controller named *notfound*.
|
||||
|
||||
Let us now implement the *notfound* Controller
|
||||
|
||||
.. _controllers:
|
||||
|
||||
Write Custom Controllers
|
||||
------------------------
|
||||
The easiest way to implement our custom *notfound* error controller is to
|
||||
add it to ``test_project.root.RootController`` class
|
||||
(typically in test_project/controllers/root.py)::
|
||||
|
||||
from pecan import expose
|
||||
from webob.exc import status_map
|
||||
|
||||
|
||||
class RootController(object):
|
||||
|
||||
@expose(generic=True, template='index.html')
|
||||
def index(self):
|
||||
return dict()
|
||||
|
||||
@index.when(method='POST')
|
||||
def index_post(self, q):
|
||||
redirect('http://pecan.readthedocs.org/en/latest/search.html?q=%s' % q)
|
||||
|
||||
|
||||
## custom handling of '404 Page Not Found' messages
|
||||
@expose('error.html')
|
||||
def notfound(self):
|
||||
return dict(status=404, message="test_project does not have this page")
|
||||
|
||||
|
||||
@expose('error.html')
|
||||
def error(self, status):
|
||||
try:
|
||||
status = int(status)
|
||||
except ValueError:
|
||||
status = 0
|
||||
message = getattr(status_map.get(status), 'explanation', '')
|
||||
return dict(status=status, message=message)
|
||||
|
||||
|
||||
And that's it!
|
||||
|
||||
Notice that the only bit of code we added to our RootController is::
|
||||
|
||||
## custom handling of '404 Page Not Found' messages
|
||||
@expose('error.html')
|
||||
def notfound(self):
|
||||
return dict(status=404, message="test_project does not have this page")
|
||||
|
||||
We simply ``@expose`` the ``notfound`` controller with the ``error.html``
|
||||
template (which was conveniently generated for us and placed under
|
||||
test_project/templates/ when we created ``test_project``). As with any common
|
||||
controller *@expose*'d through a template, we return a dictionary of variables
|
||||
for interpolation by the template renderer.
|
||||
|
||||
Now we can modify the error template, or write a brand new one to make the 404
|
||||
error status page or ``test_project`` as pretty or fancy as we want.
|
||||
|
||||
|
||||
@@ -36,7 +36,11 @@ class StatusPersist(object):
|
||||
|
||||
|
||||
class ErrorDocumentMiddleware(object):
|
||||
|
||||
'''
|
||||
Intersects HTTP response status code, looks it up in the error map defined
|
||||
in the Pecan app config.py, and routes to the controller assigned to that
|
||||
status.
|
||||
'''
|
||||
def __init__(self, app, error_map):
|
||||
self.app = app
|
||||
self.error_map = error_map
|
||||
@@ -44,6 +48,10 @@ class ErrorDocumentMiddleware(object):
|
||||
def __call__(self, environ, start_response):
|
||||
|
||||
def replacement_start_response(status, headers, exc_info=None):
|
||||
'''
|
||||
Overrides the default response if the status is defined in the
|
||||
Pecan app error map configuration.
|
||||
'''
|
||||
try:
|
||||
status_code = int(status.split(' ')[0])
|
||||
except (ValueError, TypeError): # pragma: nocover
|
||||
@@ -60,7 +68,6 @@ class ErrorDocumentMiddleware(object):
|
||||
self.error_map[status_code]
|
||||
)
|
||||
raise ForwardRequestException(factory=factory)
|
||||
|
||||
return start_response(status, headers, exc_info)
|
||||
|
||||
app_iter = self.app(environ, replacement_start_response)
|
||||
|
||||
@@ -12,7 +12,7 @@ app = {
|
||||
'template_path': '%(confdir)s/${package}/templates',
|
||||
'debug': True,
|
||||
'errors': {
|
||||
'404': '/error/404',
|
||||
404: '/error/404',
|
||||
'__force_dict__': True
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user