문제

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(request):
    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'.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top