Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Postcard from the Pyramid view

Postcard from the Pyramid view

Overview on View Lookup features

Rach Belaid

May 07, 2013
Tweet

More Decks by Rach Belaid

Other Decks in Programming

Transcript

  1. Hello, Bonjour Rach Belaid Vim Enthousiast, Python Developer, Postgres Fan,

    Git Lover, Belgian Erlang Hobbyist, rach @rachbelaid rachbelaid.com [email protected]
  2. Adding Views There is 2 ways to add views :

    - Via config method: Configurator.add_view(...) - Via decorator @view_config(...)
  3. Example - add_view() from wsgiref.simple_server import make_server from pyramid.config import

    Configurator from pyramid.response import Response def hello_world(request): return Response('Hello world!') if __name__ == '__main__': config = Configurator() config.add_route('home', '/') config.add_view(hello_world, route_name='home') app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever()
  4. Example - view_config() from wsgiref.simple_server import make_server from pyramid.config import

    Configurator from pyramid.response import Response from pyramid.view import view_config @view_config(route_name='home') def hello_world(request): return Response('Hello world!') if __name__ == '__main__': config = Configurator() config.add_route('home', '/') config.scan() #run the app app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever()
  5. From Request to View home profile / /username welcome welcome

    home welcome profile Requests Routes Views GET POST USER? GET GET Route Matching route matching View Lookup
  6. View lookup ? After any routes matches “the view lookup

    subsystem takes over to find the most reasonable view callable for the matched route” WTF? Pyramid build a lookup resolution tree and detects conflict in the views configs. Use pviews cmd to analyse the views lookup
  7. Example - Conflict detection ... def hello_world(request): return Response('Hello world!')

    def hi_world(request): return Response('Hello world!') if __name__ == '__main__': config = Configurator() config.add_route('home', '/') config.add_view(hello_world, route_name='home') config.add_view(hi_world, route_name='home') ... FAIL! pyramid.exceptions.ConfigurationConflictError
  8. View lookup configs Pyramid allow you to configure a view

    to be matched using many parameters - route name - request method : POST, GET, ... - xhr - request params - match params - custom predicates function
  9. Example - View Lookup route name ... def hello_world(request): return

    Response('Hello world!') def hi_world(request): return Response('Hello world!') if __name__ == '__main__': config = Configurator() config.add_route('test1', '/test1') config.add_route('test2', '/test2') config.add_view(hello_world, route_name='test1') config.add_view(hi_world, route_name='test2') ...
  10. Example - View Lookup request method ... @view_config(route_name='test', request_method='GET') def

    hello_world(request): return Response('Hello world!') @view_config(route_name='test', request_method='POST') def thanks_you(request): return Response('Thanks you') if __name__ == '__main__': config = Configurator() config.add_route('test', '/test') config.scan() ...
  11. Example - View Lookup Xhr ... @view_config(route_name='test') def hello_world(request): return

    Response('Hello world!') @view_config(route_name='test', xhr=True) def hello_world_xhr(request): val = json.dumps({'response':'Hello World'}) return Response(val) if __name__ == '__main__': config = Configurator() config.add_route('test', '/test') config.scan() ...
  12. Example - View Lookup request param ... @view_config(route_name='welcome') def welcome_view(request):

    return Response('Hello') @view_config(route_name='welcome', request_param='submit=signup') def signup_view(request): return Response('Signup') @view_config(route_name='welcome', request_param='submit=signin') def signin_view(request): return Response('Signin') if __name__ == '__main__': config = Configurator() config.add_route('welcome', '/') config.scan() ...
  13. Example - View Lookup match param ... @view_config(route_name='action', match_param='action=hello') def

    hello_view(request): return Response('Hello') @view_config(route_name='action', match_param='action=bye') def bye_view(request): return Response('Bye Bye') @view_config(route_name='action', match_param='action') def bye_view(request): return Response('Let’s continue') if __name__ == '__main__': config = Configurator() config.add_route('action', '/{action:\w+}') config.scan() ...
  14. Example - View Lookup custom predicate ... def useless_predicate(info, request):

    from datetime import date today = date.today() return today.day == 29 && today.month == 2 @view_config(route_name='home', custom_predicate=useless_predicate) def useless_view(request): return Response('Leap year') if __name__ == '__main__': config = Configurator() config.add_route('home', '/') config.scan() ...
  15. Pyramid Views: Function, Method, Class @view_config(route_name='test') def test(request): return Response('ok')

    Function class Test(object): def __init__(self, request): self.request = request @view_config(route_name='test') def test(self): return Response('ok') Method @view_config(route_name='test') class Test(object): def __init__(self, request): self.request = request def __call__(self): return Response('ok') Class
  16. Class base views - example from ... class RESTView(object): def

    __init__(self, request): self.request = request @view_config(route_name='rest', request_method='GET') def get(self): return Response('get') @view_config(route_name='rest', request_method='POST') def post(self): return Response('post') @view_config(route_name='rest', request_method='DELETE') def delete(self): return Response('delete')
  17. Example - view default ... @view_defaults(route_name='rest') class RESTView(object): def __init__(self,

    request): self.request = request @view_config(request_method='GET') def get(self): return Response('get') @view_config(request_method='POST') def post(self): return Response('post') @view_config(request_method='DELETE') def delete(self): return Response('delete')
  18. Class base views - example for decorator haters @view_defaults(route_name='rest') class

    RESTView(object): def __init__(self, request): self.request = request def get(self): return Response('get') def post(self): return Response('post') def delete(self): return Response('delete') if __name__ == '__main__': config = Configurator() config.add_route('rest', '/rest') config.add_view(RESTView, attr='get', request_method='GET') config.add_view(RESTView, attr='post', request_method='POST') config.add_view(RESTView, attr='delete', request_method='DELETE')
  19. Renderers A view don’t always need to return a Response

    object. If not then Pyramid attempt to use a renderer to construct a response
  20. Built-in Renderers - string - JSON - JSONP - Chameleon

    Template : *.pt or *.txt - Mako Template : *.mak or *.mako
  21. Class base views - example with renderer ... @view_defaults(route_name='rest', renderer='JSON')

    class RESTView(object): def __init__(self, request): self.request = request @view_config(request_method='GET') def get(self): return {'method':'GET'} @view_config(request_method='POST') def post(self): return {'method':'POST'} @view_config(request_method='DELETE') def delete(self): return {'method':'DELETE'}
  22. Renderers & Templates - When the renderer is set to

    a Template. The view needs to return a dict to populate the context renderer='templates/home.pt' renderer='package:templates/home.mak' renderer='home.jinja2'
  23. Response adapter To allow views to return objects without requiring

    a renderer to convert def string_response_adapter(s): response = Response(s) return response config.add_response_adapter(string_response_adapter, str)
  24. 404 When Pyramid can’t map a URL to a view

    code, it invokes a not found view from pyramid.view import notfound_view_config @notfound_view_config() def notfound(request): return Response('Not Found, dude', status='404 Not Found') config.add_notfound_view(notfound) Or
  25. 403 When Pyramid can’t authorize view based on the authorization

    policy, it invokes a forbidden view from pyramid.view import forbidden_view_config @forbidden_view_config() def forbidden(request): return Response('forbidden') config.add_forbidden_view(forbidden_view) Or
  26. HTTP Exceptions HTTP Exceptions can be raised or returned pyramid.httpexceptions.*

    (200 -> 511) from pyramid.httpexceptions import HTTPNotFound, HTTPForbidden def do_something_notfound(request): return HTTPNotFound() def do_something_forbidden(request): raise HTTPForbidden()
  27. Static view Pyramid makes it possible to serve up static

    asset files from a directory on a filesystem The name represents a URL prefix config.add_static_view(name='static', path='/var/www/static')
  28. Missing the good old days? - You can attach view

    directly to a route config.add_route('home', '/', view= function_view) - You can event use Python dotted name config.add_route('home', '/', view= 'module.function_view')