werkzeug mapping urls to views (via endpoint)
Starting using werkzeug, i try to map urls (from a file urls.py) to views (from a folder views and then in different files to manage differents kinds of view), my folder organisation looks like that :
myapp/
application.py
urls.py
views/
__init__.py
common.py
places.py
...
my urls.py files looks like that:
from werkzeug.routing import Map, Rule
url_map = Map([
Rule('/places', endpoint='places.overview')
])
and obviously i got that piece in the views/places.py file :
def overview(requ开发者_StackOverflow社区est):
mycode...
render_template('places.html', extra...)
Most of werkzeug examples show the utilisation of the decorator expose to attach urls to views. It's practical for an app with 5 or 6 urls but can become a hell when you got more...
Is there a simple way to map the urls directly to the views???
Thanks.Here is a simplified example:
import views
def app(environ, start_response):
urls = url_map.bind_to_environ(environ)
request = Request(environ)
endpoint, params = urls.match()
names = endpoint.split('.')
view = views
for name in names:
if not hasattr(view, name):
__import__(view.__name__, None, None, [name])
view = getattr(view, name)
try:
response = view(request)
except werkzeug.exceptions.HTTPException, exc:
response = exc
return response(environ, start_response)
import letters # our views module
url_map = Map([
Rule('/letters', endpoint=letters.index),
Rule('/letters/<int:item_id>', endpoint=letters.item),
Rule('/letters/<string:section_slug>', endpoint=letters.index),
Rule('/letters/<string:section_slug>/<int:item_id>',
endpoint=letters.item),
])
endpoint can be anything, including function, so you can just skip import magic from Denis's example
I'm not sure if it is preferred way to tackle this problem (I haven't found any similar example in werkzeug repo and I'm still only playing with this lib) but it is also possible to simply subclass Rule:
class CoolRule(Rule):
def __init__(self, view, *args, **kwargs):
self.view = view
super(CoolRule, self).__init__(*args, **kwargs)
def empty(self):
"""We need this method if we want to use
Submounts or Subdomain factories
"""
defaults = dict(self.defaults) if self.defaults else None
return CoolRule(self.view, self.rule, defaults, self.subdomain,
self.methods, self.build_only, self.endpoint,
self.strict_slashes, self.redirect_to,
self.alias, self.host)
_url_map = Map([
CoolRule(user.views.login, '/login', endpoint='user-login'),
CoolRule(user.views.logout, '/logout', endpoint='user-logout'),
])
def dispatch(request):
urls = _url_map.bind_to_environ(request.environ)
rule, arguments = urls.match(return_rule=True)
return rule.view(request, **arguments)
In that way you can preserve layer of view naming abstraction and avoid strange magic with 'string importing'.
精彩评论