summaryrefslogtreecommitdiff
path: root/docs/narr/router.rst
blob: f9e98373cea8f0e1be48530f1d18bb15d47866a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
.. index::
   single: request processing
   single: request
   single: router

.. _router_chapter:

Request Processing
==================

Once a :app:`Pyramid` application is up and running, it is ready to
accept requests and return responses.

What happens from the time a :term:`WSGI` request enters a
:app:`Pyramid` application through to the point that
:app:`Pyramid` hands off a response back to WSGI for upstream
processing?

#. A user initiates a request from his browser to the hostname and
   port number of the WSGI server used by the :app:`Pyramid`
   application.

#. The WSGI server used by the :app:`Pyramid` application passes
   the WSGI environment to the ``__call__`` method of the
   :app:`Pyramid` :term:`router` object.

#. A :term:`request` object is created based on the WSGI environment.

#. The :term:`application registry` and the :term:`request` object
   created in the last step are pushed on to the :term:`thread local`
   stack that :app:`Pyramid` uses to allow the functions named
   :func:`pyramid.threadlocal.get_current_request` and
   :func:`pyramid.threadlocal.get_current_registry` to work.

#. A :class:`pyramid.events.NewRequest` :term:`event` is sent to any
   subscribers.

#. If any :term:`route` has been defined within application
   configuration, the :app:`Pyramid` :term:`router` calls a
   :term:`URL dispatch` "route mapper."  The job of the mapper is to
   examine the request to determine whether any user-defined
   :term:`route` matches the current WSGI environment.  The
   :term:`router` passes the request as an argument to the mapper.

#. If any route matches, the request is mutated; a ``matchdict`` and
   ``matched_route`` attributes are added to the request object; the
   former contains a dictionary representign the matched dynamic
   elements of the request's ``PATH_INFO`` value, the latter contains
   the :class:`pyramid.interfaces.IRoute` object representing the
   route which matched.  The root object associated with the route
   found is also generated: if the :term:`route configuration` which
   matched has an associated a ``factory`` argument, this factory is
   used to generate the root object, otherwise a default :term:`root
   factory` is used.

#. If a route match was *not* found, and a ``root_factory`` argument
   was passed to the :term:`Configurator` constructor, that callable
   is used to generate the root object.  If the ``root_factory``
   argument passed to the Configurator constructor was ``None``, a
   default root factory is used to generate a root object.

#. The :app:`Pyramid` router calls a "traverser" function with the
   root object and the request.  The traverser function attempts to
   traverse the root object (using any existing ``__getitem__`` on the
   root object and subobjects) to find a :term:`context`.  If the root
   object has no ``__getitem__`` method, the root itself is assumed to
   be the context.  The exact traversal algorithm is described in
   :ref:`traversal_chapter`. The traverser function returns a
   dictionary, which contains a :term:`context` and a :term:`view
   name` as well as other ancillary information.

#. The request is decorated with various names returned from the
   traverser (such as ``context``, ``view_name``, and so forth), so
   they can be accessed via e.g. ``request.context`` within
   :term:`view` code.

#. A :class:`pyramid.events.ContextFound` :term:`event` is
   sent to any subscribers.

#. :app:`Pyramid` looks up a :term:`view` callable using the
   context, the request, and the view name.  If a view callable
   doesn't exist for this combination of objects (based on the type of
   the context, the type of the request, and the value of the view
   name, and any :term:`predicate` attributes applied to the view
   configuration), :app:`Pyramid` raises a
   :class:`pyramid.exceptions.NotFound` exception, which is meant
   to be caught by a surrounding exception handler.

#. If a view callable was found, :app:`Pyramid` attempts to call
   the view function.

#. If an :term:`authorization policy` is in use, and the view was
   protected by a :term:`permission`, :app:`Pyramid` passes the
   context, the request, and the view_name to a function which
   determines whether the view being asked for can be executed by the
   requesting user, based on credential information in the request and
   security information attached to the context.  If it returns
   ``True``, :app:`Pyramid` calls the view callable to obtain a
   response.  If it returns ``False``, it raises a
   :class:`pyramid.exceptions.Forbidden` exception, which is meant
   to be called by a surrounding exception handler.

#. If any exception was raised within a :term:`root factory`, by
   :term:`traversal`, by a :term:`view callable` or by
   :app:`Pyramid` itself (such as when it raises
   :class:`pyramid.exceptions.NotFound` or
   :class:`pyramid.exceptions.Forbidden`), the router catches the
   exception, and attaches it to the request as the ``exception``
   attribute.  It then attempts to find a :term:`exception view` for
   the exception that was caught.  If it finds an exception view
   callable, that callable is called, and is presumed to generate a
   response.  If an :term:`exception view` that matches the exception
   cannot be found, the exception is reraised.

#. The following steps occur only when a :term:`response` could be
   successfully generated by a normal :term:`view callable` or an
   :term:`exception view` callable.  :app:`Pyramid` will attempt to execute
   any :term:`response callback` functions attached via
   :meth:`pyramid.request.Request.add_response_callback`.  A
   :class:`pyramid.events.NewResponse` :term:`event` is then sent to any
   subscribers.  The response object's ``app_iter``, ``status``, and
   ``headerlist`` attributes are then used to generate a WSGI response.  The
   response is sent back to the upstream WSGI server.

#. :app:`Pyramid` will attempt to execute any :term:`finished
   callback` functions attached via
   :meth:`pyramid.request.Request.add_finished_callback`.

#. The :term:`thread local` stack is popped.

.. image:: router.png

This is a very high-level overview that leaves out various details.
For more detail about subsystems invoked by the :app:`Pyramid` router
such as traversal, URL dispatch, views, and event processing, see
:ref:`urldispatch_chapter`, :ref:`views_chapter`, and
:ref:`events_chapter`.