<p>您可以说,在view函数之外提取代码是非常好的。你知道吗</p>
<p>就我个人而言,我非常喜欢檐口为restapi所做的工作:<a href="https://cornice.readthedocs.io/en/latest/validation.html" rel="nofollow noreferrer">https://cornice.readthedocs.io/en/latest/validation.html</a></p>
<p>例如,从上面的链接:</p>
<pre><code>from cornice import Service
foo = Service(name='foo', path='/foo')
def has_paid(request, **kwargs):
if not 'X-Verified' in request.headers:
request.errors.add('header', 'X-Verified', 'You need to provide a token')
@foo.get(validators=has_paid)
def get_value(request):
"""Returns the value.
"""
return 'Hello'
</code></pre>
<p>我在一个应用程序上工作,其中既有檐口端点,也有用<code>@view_config</code>声明的常规视图,因此我编写了一个decorator,可以用来包装Colander模式类(<a href="https://docs.pylonsproject.org/projects/colander/en/latest/" rel="nofollow noreferrer">https://docs.pylonsproject.org/projects/colander/en/latest/</a>)。你知道吗</p>
<p>装饰师看起来像这样:</p>
<pre><code>from collections import defaultdict
from pyramid.renderers import render_to_response
import colander
from translationstring import TranslationString
class PreValidator:
def __init__(self, schema_class, renderer, on_invalid=None, extra_vars=None):
self.schema_class = schema_class
self.renderer = renderer
self.on_invalid = on_invalid
self.extra_vars = extra_vars
def __call__(self, wrapped):
def wrapper(context, request):
schema = self.schema_class().bind(request=request)
try:
values = schema.deserialize(request.POST.mixed())
request.validated = values
return wrapped(context, request)
except colander.Invalid as e:
if hasattr(self.on_invalid, '__call__'):
self.on_invalid(request)
errors = dict([(c.node.name, c.messages()) for c in e.children])
general_errors = e.messages()
if len(general_errors) > 0:
errors['_general'] = general_errors
for _, msgs in errors.items():
for i, msg in enumerate(msgs):
if type(msg) == TranslationString:
msgs[i] = request.localizer.translate(msg)
for_renderer = dict(
values=defaultdict(lambda: '', request.POST.items()),
errors=errors,
)
if hasattr(self.extra_vars, '__call__'):
self.extra_vars(request, for_renderer)
return render_to_response(
self.renderer, for_renderer, request, response=request.response)
return wrapper
</code></pre>
<p>它的用法类似于:</p>
<pre><code>from colander import (
Schema,
SchemaNode,
String,
Invalid,
deferred,
)
class LoginSchema(Schema):
# here you would do more complex validation
email = SchemaNode(String())
password = SchemaNode(String())
def extra_vars(request, templ_vars):
# in case you need to set again some value
pass
@view_config(
route_name='login',
request_method='POST',
renderer='/website/login.jinja2',
decorator=PreValidator(
LoginSchema,
'/website/login.jinja2',
on_invalid=lambda r: r.POST.pop('password', None),
extra_vars=extra_vars),
)
def login_post(request):
# here you know the request is valid
do_something(request.validated['email'], request.validated['password'])
return HTTPFound('/')
</code></pre>
<p>我不是说你应该按原样使用它,但我想看看别人是怎么做的会有所帮助。你知道吗</p>
<p>另外,请确保使用工厂/上下文(即使不使用遍历路由)和金字塔ACL,以确保从视图函数中提取尽可能多的内容。你知道吗</p>