Error handling with Python + Pylons
What is the proper way to handle errors with Python + Pylons?
开发者_如何转开发Say a user sets a password via a form that, when passed to a model class via the controller, throws an error because it's too short. How should that error be handled so that an error message gets displayed on the web page rather than the entire script terminating to an error page?
Should there be any error handling in the controller itself?
I hope I am explaining myself clearly.
Thank you.
What are you using to validate your forms? I'm using formalchemy. It validates the input data using built-in and custom validators, and feeds a list with the errors it finds. You can then display that list in any way you want in your template.
Documentation here.
I use formencode @validate decorator. It is possible to write custom validator for it but the problem with handling exceptions that occur in the model after validation still exists.
You could write custom action decorator similar to formencode one which will handle your model exceptions and populate c.form_errors.
Not pretending to be production-ready solution, just as an example. Actually I've copied most of decorator code from pylons.decorators:
from decorator import decorator
from webob import UnicodeMultiDict
class ModelException(Exception):
pass
def handle_exceptions(form):
def wrapper(fn, self, *args,**kwargs):
try:
return fn(self, *args, **kwargs)
except ModelException, e:
errors = str(e)
params = request.POST
is_unicode_params = isinstance(params, UnicodeMultiDict)
params = params.mixed()
request.environ['pylons.routes_dict']['action'] = form
response = self._dispatch_call()
# XXX: Legacy WSGIResponse support
legacy_response = False
if hasattr(response, 'content'):
form_content = ''.join(response.content)
legacy_response = True
else:
form_content = response
response = self._py_object.response
# If the form_content is an exception response, return it
if hasattr(form_content, '_exception'):
return form_content
form_content = htmlfill.render(form_content, defaults=params,
errors=errors)
if legacy_response:
# Let the Controller merge the legacy response
response.content = form_content
return response
else:
return form_content
return decorator(wrapper)
class HelloFormSchema(Schema):
allow_extra_fields = True
filter_extra_fields = True
name = formencode.validators.UnicodeString(not_empty=True)
email = formencode.validators.UnicodeString(not_empty=True)
class HelloController(BaseController):
def new(self):
return render('/hello/new.html')
def view(self):
return 'created'
@handle_exceptions(form='new')
@validate(schema=HelloFormSchema(), form='new')
@restrict("POST")
def create(self):
#here is code interacting with model which potentially could raise exception:
if self.form_result['name'] == 'doe':
raise ModelException('user already exists!')
return redirect(url(controller='hello', action='view'))
new.html:
${h.form(h.url(controller='hello', action='create'), 'post')}
<dl>
<dt>Name</dt>
<dd>${h.text('name')}</dd>
<dt>Email</dt>
<dd>${h.text('email')}</dd>
<dd>
${h.submit('create', 'Create')}
</dd>
</dl>
${h.end_form()}
精彩评论