diff options
| author | Florian Apolloner <florian@apolloner.eu> | 2015-11-07 16:12:37 +0100 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2016-05-17 07:22:22 -0400 |
| commit | 9baf692a58de78dba13aa582098781675367c329 (patch) | |
| tree | 1926555441d0c3b13185782dce193b839d616a4a /docs | |
| parent | 05c888ffb843ba3eff06cd07b3cef5bbb513a54f (diff) | |
Fixed #26601 -- Improved middleware per DEP 0005.
Thanks Tim Graham for polishing the patch, updating the tests, and
writing documentation. Thanks Carl Meyer for shepherding the DEP.
Diffstat (limited to 'docs')
28 files changed, 311 insertions, 1172 deletions
diff --git a/docs/howto/auth-remote-user.txt b/docs/howto/auth-remote-user.txt index 1680baa92b..5bfe210458 100644 --- a/docs/howto/auth-remote-user.txt +++ b/docs/howto/auth-remote-user.txt @@ -29,10 +29,10 @@ Configuration First, you must add the :class:`django.contrib.auth.middleware.RemoteUserMiddleware` to the -:setting:`MIDDLEWARE_CLASSES` setting **after** the +:setting:`MIDDLEWARE` setting **after** the :class:`django.contrib.auth.middleware.AuthenticationMiddleware`:: - MIDDLEWARE_CLASSES = [ + MIDDLEWARE = [ '...', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.RemoteUserMiddleware', diff --git a/docs/howto/error-reporting.txt b/docs/howto/error-reporting.txt index d07404a1e9..7a51338539 100644 --- a/docs/howto/error-reporting.txt +++ b/docs/howto/error-reporting.txt @@ -57,7 +57,7 @@ not found" errors). Django sends emails about 404 errors when: * :setting:`DEBUG` is ``False``; -* Your :setting:`MIDDLEWARE_CLASSES` setting includes +* Your :setting:`MIDDLEWARE` setting includes :class:`django.middleware.common.BrokenLinkEmailsMiddleware`. If those conditions are met, Django will email the users listed in the @@ -78,7 +78,7 @@ behavior is from broken Web bots too. before other middleware that intercepts 404 errors, such as :class:`~django.middleware.locale.LocaleMiddleware` or :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`. - Put it towards the top of your :setting:`MIDDLEWARE_CLASSES` setting. + Put it towards the top of your :setting:`MIDDLEWARE` setting. You can tell Django to stop reporting particular 404s by tweaking the :setting:`IGNORABLE_404_URLS` setting. It should be a list of compiled diff --git a/docs/ref/applications.txt b/docs/ref/applications.txt index be761505fe..53d9bcd9b5 100644 --- a/docs/ref/applications.txt +++ b/docs/ref/applications.txt @@ -37,8 +37,8 @@ projects. Applications include some combination of models, views, templates, template tags, static files, URLs, middleware, etc. They're generally wired into projects with the :setting:`INSTALLED_APPS` setting and optionally with other -mechanisms such as URLconfs, the :setting:`MIDDLEWARE_CLASSES` setting, or -template inheritance. +mechanisms such as URLconfs, the :setting:`MIDDLEWARE` setting, or template +inheritance. It is important to understand that a Django application is just a set of code that interacts with various parts of the framework. There's no such thing as diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index e4af02c1a2..5057ef18b6 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -491,19 +491,19 @@ The following checks are run if you use the :option:`check --deploy` option: * **security.W001**: You do not have :class:`django.middleware.security.SecurityMiddleware` in your - :setting:`MIDDLEWARE_CLASSES` so the :setting:`SECURE_HSTS_SECONDS`, + :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES` so the :setting:`SECURE_HSTS_SECONDS`, :setting:`SECURE_CONTENT_TYPE_NOSNIFF`, :setting:`SECURE_BROWSER_XSS_FILTER`, and :setting:`SECURE_SSL_REDIRECT` settings will have no effect. * **security.W002**: You do not have :class:`django.middleware.clickjacking.XFrameOptionsMiddleware` in your - :setting:`MIDDLEWARE_CLASSES`, so your pages will not be served with an + :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, so your pages will not be served with an ``'x-frame-options'`` header. Unless there is a good reason for your site to be served in a frame, you should consider enabling this header to help prevent clickjacking attacks. * **security.W003**: You don't appear to be using Django's built-in cross-site request forgery protection via the middleware (:class:`django.middleware.csrf.CsrfViewMiddleware` is not in your - :setting:`MIDDLEWARE_CLASSES`). Enabling the middleware is the safest + :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`). Enabling the middleware is the safest approach to ensure you don't leave any holes. * **security.W004**: You have not set a value for the :setting:`SECURE_HSTS_SECONDS` setting. If your entire site is served only @@ -540,7 +540,7 @@ The following checks are run if you use the :option:`check --deploy` option: sessions. * **security.W011**: You have :class:`django.contrib.sessions.middleware.SessionMiddleware` in your - :setting:`MIDDLEWARE_CLASSES`, but you have not set + :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, but you have not set :setting:`SESSION_COOKIE_SECURE` to ``True``. Using a secure-only session cookie makes it more difficult for network traffic sniffers to hijack user sessions. @@ -554,7 +554,7 @@ The following checks are run if you use the :option:`check --deploy` option: sessions. * **security.W014**: You have :class:`django.contrib.sessions.middleware.SessionMiddleware` in your - :setting:`MIDDLEWARE_CLASSES`, but you have not set + :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, but you have not set :setting:`SESSION_COOKIE_HTTPONLY` to ``True``. Using an ``HttpOnly`` session cookie makes it more difficult for cross-site scripting attacks to hijack user sessions. @@ -571,7 +571,7 @@ The following checks are run if you use the :option:`check --deploy` option: deployment. * **security.W019**: You have :class:`django.middleware.clickjacking.XFrameOptionsMiddleware` in your - :setting:`MIDDLEWARE_CLASSES`, but :setting:`X_FRAME_OPTIONS` is not set to + :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, but :setting:`X_FRAME_OPTIONS` is not set to ``'DENY'``. The default is ``'SAMEORIGIN'``, but unless there is a good reason for your site to serve other parts of itself in a frame, you should change it to ``'DENY'``. diff --git a/docs/ref/clickjacking.txt b/docs/ref/clickjacking.txt index abac81dcd8..2f72e18d2f 100644 --- a/docs/ref/clickjacking.txt +++ b/docs/ref/clickjacking.txt @@ -56,9 +56,9 @@ Setting ``X-Frame-Options`` for all responses To set the same ``X-Frame-Options`` value for all responses in your site, put ``'django.middleware.clickjacking.XFrameOptionsMiddleware'`` to -:setting:`MIDDLEWARE_CLASSES`:: +:setting:`MIDDLEWARE`:: - MIDDLEWARE_CLASSES = [ + MIDDLEWARE = [ ... 'django.middleware.clickjacking.XFrameOptionsMiddleware', ... diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index eed7d4451c..66b116ad35 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -41,8 +41,8 @@ For reference, here are the requirements: defined in your :setting:`TEMPLATES` as well as :class:`django.contrib.auth.middleware.AuthenticationMiddleware` and :class:`django.contrib.messages.middleware.MessageMiddleware` to - :setting:`MIDDLEWARE_CLASSES`. (These are all active by default, so - you only need to do this if you've manually tweaked the settings.) + :setting:`MIDDLEWARE`. These are all active by default, so you only need to + do this if you've manually tweaked the settings. 4. Determine which of your application's models should be editable in the admin interface. diff --git a/docs/ref/contrib/flatpages.txt b/docs/ref/contrib/flatpages.txt index 3326a93ea8..580f864c34 100644 --- a/docs/ref/contrib/flatpages.txt +++ b/docs/ref/contrib/flatpages.txt @@ -53,7 +53,7 @@ Then either: or: 3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'`` - to your :setting:`MIDDLEWARE_CLASSES` setting. + to your :setting:`MIDDLEWARE` setting. 4. Run the command :djadmin:`manage.py migrate <migrate>`. @@ -144,8 +144,7 @@ can do all of the work. methods. Only requests which are successfully routed to a view via normal URL resolution apply view middleware. -Note that the order of :setting:`MIDDLEWARE_CLASSES` matters. Generally, you -can put +Note that the order of :setting:`MIDDLEWARE` matters. Generally, you can put :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware` at the end of the list. This means it will run first when processing the response, and ensures that any other response-processing middlewares see the real flatpage diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt index d425899cd9..414cf21116 100644 --- a/docs/ref/contrib/messages.txt +++ b/docs/ref/contrib/messages.txt @@ -27,14 +27,14 @@ already contains all the settings required to enable message functionality: * ``'django.contrib.messages'`` is in :setting:`INSTALLED_APPS`. -* :setting:`MIDDLEWARE_CLASSES` contains +* :setting:`MIDDLEWARE` contains ``'django.contrib.sessions.middleware.SessionMiddleware'`` and ``'django.contrib.messages.middleware.MessageMiddleware'``. The default :ref:`storage backend <message-storage-backends>` relies on :doc:`sessions </topics/http/sessions>`. That's why ``SessionMiddleware`` must be enabled and appear before ``MessageMiddleware`` in - :setting:`MIDDLEWARE_CLASSES`. + :setting:`MIDDLEWARE`. * The ``'context_processors'`` option of the ``DjangoTemplates`` backend defined in your :setting:`TEMPLATES` setting contains @@ -42,8 +42,8 @@ already contains all the settings required to enable message functionality: If you don't want to use messages, you can remove ``'django.contrib.messages'`` from your :setting:`INSTALLED_APPS`, the -``MessageMiddleware`` line from :setting:`MIDDLEWARE_CLASSES`, and the -``messages`` context processor from :setting:`TEMPLATES`. +``MessageMiddleware`` line from :setting:`MIDDLEWARE`, and the ``messages`` +context processor from :setting:`TEMPLATES`. Configuring the message engine ============================== diff --git a/docs/ref/contrib/redirects.txt b/docs/ref/contrib/redirects.txt index 2aadf8a45c..8af48ba8b2 100644 --- a/docs/ref/contrib/redirects.txt +++ b/docs/ref/contrib/redirects.txt @@ -18,7 +18,7 @@ To install the redirects app, follow these steps: :ref:`is installed <enabling-the-sites-framework>`. 2. Add ``'django.contrib.redirects'`` to your :setting:`INSTALLED_APPS` setting. 3. Add ``'django.contrib.redirects.middleware.RedirectFallbackMiddleware'`` - to your :setting:`MIDDLEWARE_CLASSES` setting. + to your :setting:`MIDDLEWARE` setting. 4. Run the command :djadmin:`manage.py migrate <migrate>`. How it works @@ -49,9 +49,9 @@ given ``old_path`` with a site ID that corresponds to the The middleware only gets activated for 404s -- not for 500s or responses of any other status code. -Note that the order of :setting:`MIDDLEWARE_CLASSES` matters. Generally, you -can put :class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware` -at the end of the list, because it's a last resort. +Note that the order of :setting:`MIDDLEWARE` matters. Generally, you can put +:class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware` at the +end of the list, because it's a last resort. For more on middleware, read the :doc:`middleware docs </topics/http/middleware>`. diff --git a/docs/ref/contrib/sites.txt b/docs/ref/contrib/sites.txt index 2f312d04e0..ec2c1bf2b2 100644 --- a/docs/ref/contrib/sites.txt +++ b/docs/ref/contrib/sites.txt @@ -405,8 +405,8 @@ If you often use this pattern:: there is simple way to avoid repetitions. Add :class:`django.contrib.sites.middleware.CurrentSiteMiddleware` to -:setting:`MIDDLEWARE_CLASSES`. The middleware sets the ``site`` attribute on -every request object, so you can use ``request.site`` to get the current site. +:setting:`MIDDLEWARE`. The middleware sets the ``site`` attribute on every +request object, so you can use ``request.site`` to get the current site. How Django uses the sites framework =================================== diff --git a/docs/ref/csrf.txt b/docs/ref/csrf.txt index f59b45646d..277fd85720 100644 --- a/docs/ref/csrf.txt +++ b/docs/ref/csrf.txt @@ -27,10 +27,10 @@ How to use it To take advantage of CSRF protection in your views, follow these steps: -1. The CSRF middleware is activated by default in the - :setting:`MIDDLEWARE_CLASSES` setting. If you override that setting, remember - that ``'django.middleware.csrf.CsrfViewMiddleware'`` should come before any - view middleware that assume that CSRF attacks have been dealt with. +1. The CSRF middleware is activated by default in the :setting:`MIDDLEWARE` + setting. If you override that setting, remember that + ``'django.middleware.csrf.CsrfViewMiddleware'`` should come before any view + middleware that assume that CSRF attacks have been dealt with. If you disabled it, which is not recommended, you can use :func:`~django.views.decorators.csrf.csrf_protect` on particular views diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt index 49062d3474..1e582d5724 100644 --- a/docs/ref/middleware.txt +++ b/docs/ref/middleware.txt @@ -77,6 +77,36 @@ issued by the middleware. * Sends broken link notification emails to :setting:`MANAGERS` (see :doc:`/howto/error-reporting`). +Exception middleware +-------------------- + +.. module:: django.middleware.exception + :synopsis: Middleware to return responses for exceptions. + +.. class:: ExceptionMiddleware + +.. versionadded:: 1.10 + +Catches exceptions raised during the request/response cycle and returns the +appropriate response. + +* :class:`~django.http.Http404` is processed by + :data:`~django.conf.urls.handler404` (or a more friendly debug page if + :setting:`DEBUG=True <DEBUG>`). +* :class:`~django.core.exceptions.PermissionDenied` is processed + by :data:`~django.conf.urls.handler403`. +* ``MultiPartParserError`` is processed by :data:`~django.conf.urls.handler400`. +* :class:`~django.core.exceptions.SuspiciousOperation` is processed by + :data:`~django.conf.urls.handler400` (or a more friendly debug page if + :setting:`DEBUG=True <DEBUG>`). +* Any other exception is processed by :data:`~django.conf.urls.handler500` + (or a more friendly debug page if :setting:`DEBUG=True <DEBUG>`). + +Django uses this middleware regardless of whether or not you include it in +:setting:`MIDDLEWARE`, however, you may want to subclass if your own middleware +needs to transform any of these exceptions into the appropriate responses. +:class:`~django.middleware.locale.LocaleMiddleware` does this, for example. + GZip middleware --------------- diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index 64bd5960cd..96f5300f8b 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -176,9 +176,9 @@ All attributes should be considered read-only, unless stated otherwise. An instance of :class:`~django.urls.ResolverMatch` representing the resolved URL. This attribute is only set after URL resolving took place, - which means it's available in all views but not in middleware methods - which are executed before URL resolving takes place (like - ``process_request()``, you can use ``process_view()`` instead). + which means it's available in all views but not in middleware which are + executed before URL resolving takes place (you can use it in + :meth:`process_view` though). Attributes set by application code ---------------------------------- @@ -210,7 +210,7 @@ Attributes set by middleware Some of the middleware included in Django's contrib apps set attributes on the request. If you don't see the attribute on a request, be sure the appropriate -middleware class is listed in :setting:`MIDDLEWARE_CLASSES`. +middleware class is listed in :setting:`MIDDLEWARE`. .. attribute:: HttpRequest.session @@ -257,7 +257,9 @@ Methods behind multiple proxies. One solution is to use middleware to rewrite the proxy headers, as in the following example:: - class MultipleProxyMiddleware(object): + from django.django.utils.deprecation import MiddlewareMixin + + class MultipleProxyMiddleware(MiddlewareMixin): FORWARDED_FOR_FIELDS = [ 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED_HOST', diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 838dde808a..a7801f715c 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -77,7 +77,7 @@ can be used as a subdomain wildcard: ``'.example.com'`` will match ``example.com``. A value of ``'*'`` will match anything; in this case you are responsible to provide your own validation of the ``Host`` header (perhaps in a middleware; if so this middleware must be listed first in -:setting:`MIDDLEWARE_CLASSES`). +:setting:`MIDDLEWARE`). Django also allows the `fully qualified domain name (FQDN)`_ of any entries. Some browsers include a trailing dot in the ``Host`` header which Django @@ -1844,6 +1844,17 @@ Example: ``"http://media.example.com/"`` :setting:`MEDIA_URL` and :setting:`STATIC_URL` must have different values. See :setting:`MEDIA_ROOT` for more details. +.. setting:: MIDDLEWARE + +``MIDDLEWARE`` +-------------- + +.. versionadded:: 1.10 + +Default:: ``None`` + +A list of middleware to use. See :doc:`/topics/http/middleware`. + .. setting:: MIDDLEWARE_CLASSES ``MIDDLEWARE_CLASSES`` @@ -1856,7 +1867,11 @@ Default:: 'django.middleware.csrf.CsrfViewMiddleware', ] -A list of middleware classes to use. See :doc:`/topics/http/middleware`. +A list of middleware classes to use. This was the default setting used in +Django 1.9 and earlier. Django 1.10 introduced a new style of middleware. If +you have an older project using this setting you should :ref:`update any +middleware you've written yourself <upgrading-middleware>` to the new style +and then use the :setting:`MIDDLEWARE` setting. .. setting:: MIGRATION_MODULES @@ -3312,6 +3327,7 @@ HTTP * :setting:`DISALLOWED_USER_AGENTS` * :setting:`FORCE_SCRIPT_NAME` * :setting:`INTERNAL_IPS` +* :setting:`MIDDLEWARE` * :setting:`MIDDLEWARE_CLASSES` * Security diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index f95ff1017f..1b527277af 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -173,6 +173,10 @@ The functions defined in this module share the following properties: middleware functionality on a per-view basis. The middleware is created with no params passed. + It assumes middleware that's compatible with the old style of Django 1.9 + and earlier (having methods like ``process_request()``, + ``process_exception()``, and ``process_response()``). + .. function:: decorator_from_middleware_with_args(middleware_class) Like ``decorator_from_middleware``, but returns a function diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index b6ac9f5c89..13e5f44d5b 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -37,6 +37,17 @@ It also now includes trigram support, using the :lookup:`trigram_similar` lookup, and the :class:`~django.contrib.postgres.search.TrigramSimilarity` and :class:`~django.contrib.postgres.search.TrigramDistance` expressions. +New-style middleware +-------------------- + +:doc:`A new style of middleware is introduced </topics/http/middleware>` to +solve the lack of strict request/response layering of the old-style of +middleware described in `DEP 0005 +<https://github.com/django/deps/blob/master/final/0005-improved-middleware.rst>`_. +You'll need to :ref:`adapt old, custom middleware <upgrading-middleware>` and +switch from the ``MIDDLEWARE_CLASSES`` setting to the new :setting:`MIDDLEWARE` +setting to take advantage of the improvements. + Official support for Unicode usernames -------------------------------------- diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt index 3ecdcca12e..21da0dca61 100644 --- a/docs/releases/1.5.txt +++ b/docs/releases/1.5.txt @@ -188,8 +188,7 @@ is an iterator. Since :class:`~django.http.StreamingHttpResponse` does not have a ``content`` attribute, middleware that needs access to the response content must test for -streaming responses and behave accordingly. See :ref:`response-middleware` for -more information. +streaming responses and behave accordingly. ``{% verbatim %}`` template tag ------------------------------- diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt index 45526eb831..7e6794a97b 100644 --- a/docs/topics/auth/default.txt +++ b/docs/topics/auth/default.txt @@ -838,7 +838,7 @@ Session invalidation on password change ``SessionAuthenticationMiddleware`` is enabled. In older versions, this protection only applies if ``django.contrib.auth.middleware.SessionAuthenticationMiddleware`` - is enabled in :setting:`MIDDLEWARE_CLASSES`. + is enabled in :setting:`MIDDLEWARE`. If your :setting:`AUTH_USER_MODEL` inherits from :class:`~django.contrib.auth.models.AbstractBaseUser` or implements its own diff --git a/docs/topics/auth/index.txt b/docs/topics/auth/index.txt index b57c2e7436..3224af74c7 100644 --- a/docs/topics/auth/index.txt +++ b/docs/topics/auth/index.txt @@ -60,7 +60,7 @@ startproject <startproject>`, these consist of two items listed in your </ref/contrib/contenttypes>`, which allows permissions to be associated with models you create. -and these items in your :setting:`MIDDLEWARE_CLASSES` setting: +and these items in your :setting:`MIDDLEWARE` setting: 1. :class:`~django.contrib.sessions.middleware.SessionMiddleware` manages :doc:`sessions </topics/http/sessions>` across requests. diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt index ad353e65e0..d955b853b4 100644 --- a/docs/topics/cache.txt +++ b/docs/topics/cache.txt @@ -447,9 +447,9 @@ Once the cache is set up, the simplest way to use caching is to cache your entire site. You'll need to add ``'django.middleware.cache.UpdateCacheMiddleware'`` and ``'django.middleware.cache.FetchFromCacheMiddleware'`` to your -:setting:`MIDDLEWARE_CLASSES` setting, as in this example:: +:setting:`MIDDLEWARE` setting, as in this example:: - MIDDLEWARE_CLASSES = [ + MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware', @@ -459,7 +459,7 @@ entire site. You'll need to add No, that's not a typo: the "update" middleware must be first in the list, and the "fetch" middleware must be last. The details are a bit obscure, but - see `Order of MIDDLEWARE_CLASSES`_ below if you'd like the full story. + see `Order of MIDDLEWARE`_ below if you'd like the full story. Then, add the following required settings to your Django settings file: @@ -1217,11 +1217,11 @@ Example:: def myview(request): ... -Order of ``MIDDLEWARE_CLASSES`` -=============================== +Order of ``MIDDLEWARE`` +======================= If you use caching middleware, it's important to put each half in the right -place within the :setting:`MIDDLEWARE_CLASSES` setting. That's because the cache +place within the :setting:`MIDDLEWARE` setting. That's because the cache middleware needs to know which headers by which to vary the cache storage. Middleware always adds something to the ``Vary`` response header when it can. diff --git a/docs/topics/http/_images/middleware.graffle b/docs/topics/http/_images/middleware.graffle deleted file mode 100644 index cdefd4b810..0000000000 --- a/docs/topics/http/_images/middleware.graffle +++ /dev/null @@ -1,957 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>ActiveLayerIndex</key> - <integer>0</integer> - <key>ApplicationVersion</key> - <array> - <string>com.omnigroup.OmniGrafflePro</string> - <string>139.16.0.171715</string> - </array> - <key>AutoAdjust</key> - <true/> - <key>BackgroundGraphic</key> - <dict> - <key>Bounds</key> - <string>{{0, 0}, {559.28997802734375, 782.8900146484375}}</string> - <key>Class</key> - <string>SolidGraphic</string> - <key>ID</key> - <integer>2</integer> - <key>Style</key> - <dict> - <key>shadow</key> - <dict> - <key>Draws</key> - <string>NO</string> - </dict> - <key>stroke</key> - <dict> - <key>Draws</key> - <string>NO</string> - </dict> - </dict> - </dict> - <key>BaseZoom</key> - <integer>0</integer> - <key>CanvasOrigin</key> - <string>{0, 0}</string> - <key>ColumnAlign</key> - <integer>1</integer> - <key>ColumnSpacing</key> - <real>36</real> - <key>CreationDate</key> - <string>2012-12-09 18:55:12 +0000</string> - <key>Creator</key> - <string>Aymeric Augustin</string> - <key>DisplayScale</key> - <string>1.000 cm = 1.000 cm</string> - <key>GraphDocumentVersion</key> - <integer>8</integer> - <key>GraphicsList</key> - <array> - <dict> - <key>Bounds</key> - <string>{{144, 405}, {369, 27}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>33</integer> - <key>Shape</key> - <string>Bezier</string> - <key>ShapeData</key> - <dict> - <key>UnitPoints</key> - <array> - <string>{-0.5, -0.5}</string> - <string>{-0.5, -0.5}</string> - <string>{0.47959183673469341, -0.5}</string> - <string>{0.47959183673469408, -0.5}</string> - <string>{0.47959183673469341, -0.5}</string> - <string>{0.5, 0}</string> - <string>{0.5, 0}</string> - <string>{0.5, 0}</string> - <string>{0.47959183673469408, 0.5}</string> - <string>{0.47959183673469408, 0.5}</string> - <string>{0.47959183673469408, 0.5}</string> - <string>{-0.5, 0.5}</string> - <string>{-0.5, 0.5}</string> - <string>{-0.5, 0.5}</string> - <string>{-0.47560975609756084, 0}</string> - <string>{-0.47560975609756084, 0}</string> - <string>{-0.47560975609756084, 0}</string> - <string>{-0.5, -0.5}</string> - </array> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 view function}</string> - </dict> - </dict> - <dict> - <key>Bounds</key> - <string>{{229.5, 238.5}, {297, 36}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>31</integer> - <key>Rotation</key> - <real>270</real> - <key>Shape</key> - <string>AdjustableArrow</string> - <key>ShapeData</key> - <dict> - <key>width</key> - <real>27</real> - </dict> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.8</string> - <key>b</key> - <string>1</string> - <key>g</key> - <string>1</string> - <key>r</key> - <string>1</string> - </dict> - <key>MiddleFraction</key> - <real>0.70634919404983521</real> - </dict> - <key>shadow</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.4</string> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0</string> - <key>r</key> - <string>0</string> - </dict> - <key>Draws</key> - <string>NO</string> - <key>Fuzziness</key> - <real>0.0</real> - <key>ShadowVector</key> - <string>{0, 2}</string> - </dict> - <key>stroke</key> - <dict> - <key>Color</key> - <dict> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0</string> - <key>r</key> - <string>1</string> - </dict> - <key>Pattern</key> - <integer>1</integer> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;\red255\green0\blue0;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf2 process_exception}</string> - </dict> - <key>TextRelativeArea</key> - <string>{{0.125, 0.25}, {0.75, 0.5}}</string> - <key>isConnectedShape</key> - <true/> - </dict> - <dict> - <key>Bounds</key> - <string>{{328.5, 229.5}, {315, 36}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>30</integer> - <key>Rotation</key> - <real>270</real> - <key>Shape</key> - <string>AdjustableArrow</string> - <key>ShapeData</key> - <dict> - <key>width</key> - <real>27</real> - </dict> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.8</string> - <key>b</key> - <string>1</string> - <key>g</key> - <string>1</string> - <key>r</key> - <string>1</string> - </dict> - <key>MiddleFraction</key> - <real>0.70634919404983521</real> - </dict> - <key>shadow</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.4</string> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0</string> - <key>r</key> - <string>0</string> - </dict> - <key>Draws</key> - <string>NO</string> - <key>Fuzziness</key> - <real>0.0</real> - <key>ShadowVector</key> - <string>{0, 2}</string> - </dict> - <key>stroke</key> - <dict> - <key>Color</key> - <dict> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0.501961</string> - <key>r</key> - <string>0</string> - </dict> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf2 process_response}</string> - </dict> - <key>TextRelativeArea</key> - <string>{{0.125, 0.25}, {0.75, 0.5}}</string> - <key>isConnectedShape</key> - <true/> - </dict> - <dict> - <key>Bounds</key> - <string>{{283.5, 238.5}, {297, 36}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>29</integer> - <key>Rotation</key> - <real>270</real> - <key>Shape</key> - <string>AdjustableArrow</string> - <key>ShapeData</key> - <dict> - <key>width</key> - <real>27</real> - </dict> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.8</string> - <key>b</key> - <string>1</string> - <key>g</key> - <string>1</string> - <key>r</key> - <string>1</string> - </dict> - <key>MiddleFraction</key> - <real>0.70634919404983521</real> - </dict> - <key>shadow</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.4</string> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0</string> - <key>r</key> - <string>0</string> - </dict> - <key>Draws</key> - <string>NO</string> - <key>Fuzziness</key> - <real>0.0</real> - <key>ShadowVector</key> - <string>{0, 2}</string> - </dict> - <key>stroke</key> - <dict> - <key>Color</key> - <dict> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0.501961</string> - <key>r</key> - <string>0</string> - </dict> - <key>Pattern</key> - <integer>1</integer> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf2 process_template_response}</string> - </dict> - <key>TextRelativeArea</key> - <string>{{0.125, 0.25}, {0.75, 0.5}}</string> - <key>isConnectedShape</key> - <true/> - </dict> - <dict> - <key>Bounds</key> - <string>{{27, 243}, {288, 36}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>28</integer> - <key>Rotation</key> - <real>90</real> - <key>Shape</key> - <string>AdjustableArrow</string> - <key>ShapeData</key> - <dict> - <key>width</key> - <real>27</real> - </dict> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.8</string> - <key>b</key> - <string>1</string> - <key>g</key> - <string>1</string> - <key>r</key> - <string>1</string> - </dict> - <key>MiddleFraction</key> - <real>0.70634919404983521</real> - </dict> - <key>shadow</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.4</string> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0</string> - <key>r</key> - <string>0</string> - </dict> - <key>Draws</key> - <string>NO</string> - <key>Fuzziness</key> - <real>0.0</real> - <key>ShadowVector</key> - <string>{0, 2}</string> - </dict> - <key>stroke</key> - <dict> - <key>Color</key> - <dict> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0.501961</string> - <key>r</key> - <string>0</string> - </dict> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf2 process_view}</string> - </dict> - <key>TextRelativeArea</key> - <string>{{0.125, 0.25}, {0.75, 0.5}}</string> - <key>isConnectedShape</key> - <true/> - </dict> - <dict> - <key>Bounds</key> - <string>{{-40.500000000767386, 220.49999999804004}, {297, 36}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>27</integer> - <key>Rotation</key> - <real>90</real> - <key>Shape</key> - <string>AdjustableArrow</string> - <key>ShapeData</key> - <dict> - <key>width</key> - <real>27</real> - </dict> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.8</string> - <key>b</key> - <string>1</string> - <key>g</key> - <string>1</string> - <key>r</key> - <string>1</string> - </dict> - <key>MiddleFraction</key> - <real>0.70634919404983521</real> - </dict> - <key>shadow</key> - <dict> - <key>Color</key> - <dict> - <key>a</key> - <string>0.4</string> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0</string> - <key>r</key> - <string>0</string> - </dict> - <key>Draws</key> - <string>NO</string> - <key>Fuzziness</key> - <real>0.0</real> - <key>ShadowVector</key> - <string>{0, 2}</string> - </dict> - <key>stroke</key> - <dict> - <key>Color</key> - <dict> - <key>b</key> - <string>0</string> - <key>g</key> - <string>0.501961</string> - <key>r</key> - <string>0</string> - </dict> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf2 process_request}</string> - </dict> - <key>TextRelativeArea</key> - <string>{{0.125, 0.25}, {0.75, 0.5}}</string> - <key>isConnectedShape</key> - <true/> - </dict> - <dict> - <key>Bounds</key> - <string>{{360, 63}, {144, 27}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>12</integer> - <key>Magnets</key> - <array> - <string>{0, 1}</string> - <string>{0, -1}</string> - <string>{1, 0}</string> - <string>{-1, 0}</string> - </array> - <key>Shape</key> - <string>Rectangle</string> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 HttpResponse}</string> - </dict> - </dict> - <dict> - <key>Bounds</key> - <string>{{72, 63}, {144, 27}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>11</integer> - <key>Magnets</key> - <array> - <string>{0, 1}</string> - <string>{0, -1}</string> - <string>{1, 0}</string> - <string>{-1, 0}</string> - </array> - <key>Shape</key> - <string>Rectangle</string> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 HttpRequest}</string> - </dict> - </dict> - <dict> - <key>Bounds</key> - <string>{{72, 324}, {432, 27}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>10</integer> - <key>Magnets</key> - <array> - <string>{0, 1}</string> - <string>{0, -1}</string> - <string>{1, 0}</string> - <string>{-1, 0}</string> - </array> - <key>Shape</key> - <string>Rectangle</string> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>FillType</key> - <integer>2</integer> - <key>GradientAngle</key> - <real>90</real> - <key>GradientColor</key> - <dict> - <key>w</key> - <string>0.666667</string> - </dict> - </dict> - <key>stroke</key> - <dict> - <key>CornerRadius</key> - <real>5</real> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 MessageMiddleware}</string> - </dict> - </dict> - <dict> - <key>Bounds</key> - <string>{{72, 279}, {432, 27}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>9</integer> - <key>Magnets</key> - <array> - <string>{0, 1}</string> - <string>{0, -1}</string> - <string>{1, 0}</string> - <string>{-1, 0}</string> - </array> - <key>Shape</key> - <string>Rectangle</string> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>FillType</key> - <integer>2</integer> - <key>GradientAngle</key> - <real>90</real> - <key>GradientColor</key> - <dict> - <key>w</key> - <string>0.666667</string> - </dict> - </dict> - <key>stroke</key> - <dict> - <key>CornerRadius</key> - <real>5</real> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 AuthenticationMiddleware}</string> - </dict> - </dict> - <dict> - <key>Bounds</key> - <string>{{72, 234}, {432, 27}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>8</integer> - <key>Magnets</key> - <array> - <string>{0, 1}</string> - <string>{0, -1}</string> - <string>{1, 0}</string> - <string>{-1, 0}</string> - </array> - <key>Shape</key> - <string>Rectangle</string> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>FillType</key> - <integer>2</integer> - <key>GradientAngle</key> - <real>90</real> - <key>GradientColor</key> - <dict> - <key>w</key> - <string>0.666667</string> - </dict> - </dict> - <key>stroke</key> - <dict> - <key>CornerRadius</key> - <real>5</real> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 CsrfViewMiddleware}</string> - </dict> - </dict> - <dict> - <key>Bounds</key> - <string>{{72, 189}, {432, 27}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>7</integer> - <key>Magnets</key> - <array> - <string>{0, 1}</string> - <string>{0, -1}</string> - <string>{1, 0}</string> - <string>{-1, 0}</string> - </array> - <key>Shape</key> - <string>Rectangle</string> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>FillType</key> - <integer>2</integer> - <key>GradientAngle</key> - <real>90</real> - <key>GradientColor</key> - <dict> - <key>w</key> - <string>0.666667</string> - </dict> - </dict> - <key>stroke</key> - <dict> - <key>CornerRadius</key> - <real>5</real> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 SessionMiddleware}</string> - </dict> - </dict> - <dict> - <key>Bounds</key> - <string>{{72, 144}, {432, 27}}</string> - <key>Class</key> - <string>ShapedGraphic</string> - <key>ID</key> - <integer>6</integer> - <key>Magnets</key> - <array> - <string>{0, 1}</string> - <string>{0, -1}</string> - <string>{1, 0}</string> - <string>{-1, 0}</string> - </array> - <key>Shape</key> - <string>Rectangle</string> - <key>Style</key> - <dict> - <key>fill</key> - <dict> - <key>FillType</key> - <integer>2</integer> - <key>GradientAngle</key> - <real>90</real> - <key>GradientColor</key> - <dict> - <key>w</key> - <string>0.666667</string> - </dict> - </dict> - <key>stroke</key> - <dict> - <key>CornerRadius</key> - <real>5</real> - </dict> - </dict> - <key>Text</key> - <dict> - <key>Text</key> - <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 -\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 CommonMiddleware}</string> - </dict> - </dict> - </array> - <key>GridInfo</key> - <dict> - <key>ShowsGrid</key> - <string>YES</string> - <key>SnapsToGrid</key> - <string>YES</string> - </dict> - <key>GuidesLocked</key> - <string>NO</string> - <key>GuidesVisible</key> - <string>YES</string> - <key>HPages</key> - <integer>1</integer> - <key>ImageCounter</key> - <integer>1</integer> - <key>KeepToScale</key> - <false/> - <key>Layers</key> - <array> - <dict> - <key>Lock</key> - <string>NO</string> - <key>Name</key> - <string>Calque 1</string> - <key>Print</key> - <string>YES</string> - <key>View</key> - <string>YES</string> - </dict> - </array> - <key>LayoutInfo</key> - <dict> - <key>Animate</key> - <string>NO</string> - <key>circoMinDist</key> - <real>18</real> - <key>circoSeparation</key> - <real>0.0</real> - <key>layoutEngine</key> - <string>dot</string> - <key>neatoSeparation</key> - <real>0.0</real> - <key>twopiSeparation</key> - <real>0.0</real> - </dict> - <key>LinksVisible</key> - <string>NO</string> - <key>MagnetsVisible</key> - <string>NO</string> - <key>MasterSheets</key> - <array/> - <key>ModificationDate</key> - <string>2012-12-09 19:48:54 +0000</string> - <key>Modifier</key> - <string>Aymeric Augustin</string> - <key>NotesVisible</key> - <string>NO</string> - <key>Orientation</key> - <integer>2</integer> - <key>OriginVisible</key> - <string>NO</string> - <key>PageBreaks</key> - <string>YES</string> - <key>PrintInfo</key> - <dict> - <key>NSBottomMargin</key> - <array> - <string>float</string> - <string>41</string> - </array> - <key>NSHorizonalPagination</key> - <array> - <string>coded</string> - <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string> - </array> - <key>NSLeftMargin</key> - <array> - <string>float</string> - <string>18</string> - </array> - <key>NSPaperSize</key> - <array> - <string>size</string> - <string>{595.28997802734375, 841.8900146484375}</string> - </array> - <key>NSPrintReverseOrientation</key> - <array> - <string>int</string> - <string>0</string> - </array> - <key>NSRightMargin</key> - <array> - <string>float</string> - <string>18</string> - </array> - <key>NSTopMargin</key> - <array> - <string>float</string> - <string>18</string> - </array> - </dict> - <key>PrintOnePage</key> - <false/> - <key>ReadOnly</key> - <string>NO</string> - <key>RowAlign</key> - <integer>1</integer> - <key>RowSpacing</key> - <real>36</real> - <key>SheetTitle</key> - <string>Canevas 1</string> - <key>SmartAlignmentGuidesActive</key> - <string>YES</string> - <key>SmartDistanceGuidesActive</key> - <string>YES</string> - <key>UniqueID</key> - <integer>1</integer> - <key>UseEntirePage</key> - <false/> - <key>VPages</key> - <integer>1</integer> - <key>WindowInfo</key> - <dict> - <key>CurrentSheet</key> - <integer>0</integer> - <key>ExpandedCanvases</key> - <array/> - <key>Frame</key> - <string>{{248, 4}, {694, 874}}</string> - <key>ListView</key> - <true/> - <key>OutlineWidth</key> - <integer>142</integer> - <key>RightSidebar</key> - <false/> - <key>ShowRuler</key> - <true/> - <key>Sidebar</key> - <true/> - <key>SidebarWidth</key> - <integer>120</integer> - <key>VisibleRegion</key> - <string>{{0, 0}, {559, 735}}</string> - <key>Zoom</key> - <real>1</real> - <key>ZoomValues</key> - <array> - <array> - <string>Canevas 1</string> - <real>1</real> - <real>1</real> - </array> - </array> - </dict> -</dict> -</plist> diff --git a/docs/topics/http/_images/middleware.svg b/docs/topics/http/_images/middleware.svg deleted file mode 100644 index 4da8d22da8..0000000000 --- a/docs/topics/http/_images/middleware.svg +++ /dev/null @@ -1,3 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="52 47 481 409" width="481pt" height="409pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-12-09 19:48Z</dc:date><!-- Produced by OmniGraffle Professional 5.4.2 --></metadata><defs><filter id="Shadow" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" result="blur" stdDeviation="3.488"/><feOffset in="blur" result="offset" dx="0" dy="4"/><feFlood flood-color="black" flood-opacity=".75" result="flood"/><feComposite in="flood" in2="offset" operator="in"/></filter><linearGradient x1="0" x2="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aaa"/></linearGradient><linearGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(288 144) rotate(90) scale(27)"/><font-face font-family="Courier" font-size="12" units-per-em="1000" underline-position="-178.22266" underline-thickness="57.617188" slope="0" x-height="462.40234" cap-height="594.72656" ascent="753.90625" descent="-246.09375" font-weight="500"><font-face-src><font-face-name name="Courier"/></font-face-src></font-face><linearGradient id="Obj_Gradient_2" xl:href="#Gradient" gradientTransform="translate(288 189) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_3" xl:href="#Gradient" gradientTransform="translate(288 234) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_4" xl:href="#Gradient" gradientTransform="translate(288 279) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_5" xl:href="#Gradient" gradientTransform="translate(288 324) rotate(90) scale(27)"/><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="522.94922" cap-height="717.28516" ascent="770.01953" descent="-229.98047" font-weight="500"><font-face-src><font-face-name name="Helvetica"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canevas 1</title><rect fill="white" width="559.28998" height="782.89"/><g><title>Calque 1</title><g><use xl:href="#id6_Graphic" filter="url(#Shadow)"/><use xl:href="#id7_Graphic" filter="url(#Shadow)"/><use xl:href="#id8_Graphic" filter="url(#Shadow)"/><use xl:href="#id9_Graphic" filter="url(#Shadow)"/><use xl:href="#id10_Graphic" filter="url(#Shadow)"/><use xl:href="#id11_Graphic" filter="url(#Shadow)"/><use xl:href="#id12_Graphic" filter="url(#Shadow)"/><use xl:href="#id33_Graphic" filter="url(#Shadow)"/></g><g id="id6_Graphic"><path d="M 77 144 L 499 144 C 501.76142 144 504 146.23858 504 149 L 504 166 C 504 168.76142 501.76142 171 499 171 L 77 171 C 74.238576 171 72 168.76142 72 166 C 72 166 72 166 72 166 L 72 149 C 72 146.23858 74.238576 144 77 144 C 77 144 77 144 77 144 Z" fill="url(#Obj_Gradient)"/><path d="M 77 144 L 499 144 C 501.76142 144 504 146.23858 504 149 L 504 166 C 504 168.76142 501.76142 171 499 171 L 77 171 C 74.238576 171 72 168.76142 72 166 C 72 166 72 166 72 166 L 72 149 C 72 146.23858 74.238576 144 77 144 C 77 144 77 144 77 144 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 150.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" fill="black" x="153.390625" y="11" textLength="115.21875">CommonMiddleware</tspan></text></g><g id="id7_Graphic"><path d="M 77 189 L 499 189 C 501.76142 189 504 191.23858 504 194 L 504 211 C 504 213.76142 501.76142 216 499 216 L 77 216 C 74.238576 216 72 213.76142 72 211 C 72 211 72 211 72 211 L 72 194 C 72 191.23858 74.238576 189 77 189 C 77 189 77 189 77 189 Z" fill="url(#Obj_Gradient_2)"/><path d="M 77 189 L 499 189 C 501.76142 189 504 191.23858 504 194 L 504 211 C 504 213.76142 501.76142 216 499 216 L 77 216 C 74.238576 216 72 213.76142 72 211 C 72 211 72 211 72 211 L 72 194 C 72 191.23858 74.238576 189 77 189 C 77 189 77 189 77 189 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 195.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="149.79004" y="11" textLength="122.41992">SessionMiddleware</tspan></text></g><g id="id8_Graphic"><path d="M 77 234 L 499 234 C 501.76142 234 504 236.23858 504 239 L 504 256 C 504 258.76142 501.76142 261 499 261 L 77 261 C 74.238576 261 72 258.76142 72 256 C 72 256 72 256 72 256 L 72 239 C 72 236.23858 74.238576 234 77 234 C 77 234 77 234 77 234 Z" fill="url(#Obj_Gradient_3)"/><path d="M 77 234 L 499 234 C 501.76142 234 504 236.23858 504 239 L 504 256 C 504 258.76142 501.76142 261 499 261 L 77 261 C 74.238576 261 72 258.76142 72 256 C 72 256 72 256 72 256 L 72 239 C 72 236.23858 74.238576 234 77 234 C 77 234 77 234 77 234 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 240.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="146.18945" y="11" textLength="129.62109">CsrfViewMiddleware</tspan></text></g><g id="id9_Graphic"><path d="M 77 279 L 499 279 C 501.76142 279 504 281.23858 504 284 L 504 301 C 504 303.76142 501.76142 306 499 306 L 77 306 C 74.238576 306 72 303.76142 72 301 C 72 301 72 301 72 301 L 72 284 C 72 281.23858 74.238576 279 77 279 C 77 279 77 279 77 279 Z" fill="url(#Obj_Gradient_4)"/><path d="M 77 279 L 499 279 C 501.76142 279 504 281.23858 504 284 L 504 301 C 504 303.76142 501.76142 306 499 306 L 77 306 C 74.238576 306 72 303.76142 72 301 C 72 301 72 301 72 301 L 72 284 C 72 281.23858 74.238576 279 77 279 C 77 279 77 279 77 279 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 285.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="124.58594" y="11" textLength="172.82812">AuthenticationMiddleware</tspan></text></g><g id="id10_Graphic"><path d="M 77 324 L 499 324 C 501.76142 324 504 326.23858 504 329 L 504 346 C 504 348.76142 501.76142 351 499 351 L 77 351 C 74.238576 351 72 348.76142 72 346 C 72 346 72 346 72 346 L 72 329 C 72 326.23858 74.238576 324 77 324 C 77 324 77 324 77 324 Z" fill="url(#Obj_Gradient_5)"/><path d="M 77 324 L 499 324 C 501.76142 324 504 326.23858 504 329 L 504 346 C 504 348.76142 501.76142 351 499 351 L 77 351 C 74.238576 351 72 348.76142 72 346 C 72 346 72 346 72 346 L 72 329 C 72 326.23858 74.238576 324 77 324 C 77 324 77 324 77 324 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 330.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="149.79004" y="11" textLength="122.41992">MessageMiddleware</tspan></text></g><g id="id11_Graphic"><rect x="72" y="63" width="144" height="27" fill="white"/><rect x="72" y="63" width="144" height="27" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 69.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="27.393555" y="11" textLength="79.21289">HttpRequest</tspan></text></g><g id="id12_Graphic"><rect x="360" y="63" width="144" height="27" fill="white"/><rect x="360" y="63" width="144" height="27" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(365 69.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="23.792969" y="11" textLength="86.41406">HttpResponse</tspan></text></g><path d="M 99 90 L 117 90 L 117 360 L 126 360 L 108 387 L 90 360 L 99 360 Z" fill="white" fill-opacity=".8"/><path d="M 99 90 L 117 90 L 117 360 L 126 360 L 108 387 L 90 360 L 99 360 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(115 132.125) rotate(90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="52.36621" y="11" textLength="108.01758">process_request</tspan></text><path d="M 162 117 L 180 117 L 180 378 L 189 378 L 171 405 L 153 378 L 162 378 Z" fill="white" fill-opacity=".8"/><path d="M 162 117 L 180 117 L 180 378 L 189 378 L 171 405 L 153 378 L 162 378 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(178 158) rotate(90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="59.79297" y="11" textLength="86.41406">process_view</tspan></text><path d="M 441 405 L 423 405 L 423 135 L 414 135 L 432 108 L 450 135 L 441 135 Z" fill="white" fill-opacity=".8"/><path d="M 441 405 L 423 405 L 423 135 L 414 135 L 432 108 L 450 135 L 441 135 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="4,4"/><text transform="translate(425 362.875) rotate(-90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="16.360352" y="11" textLength="180.0293">process_template_response</tspan></text><path d="M 495 405 L 477 405 L 477 117 L 468 117 L 486 90 L 504 117 L 495 117 Z" fill="white" fill-opacity=".8"/><path d="M 495 405 L 477 405 L 477 117 L 468 117 L 486 90 L 504 117 L 495 117 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(479 360.625) rotate(-90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="55.515625" y="11" textLength="115.21875">process_response</tspan></text><path d="M 387 405 L 369 405 L 369 135 L 360 135 L 378 108 L 396 135 L 387 135 Z" fill="white" fill-opacity=".8"/><path d="M 387 405 L 369 405 L 369 135 L 360 135 L 378 108 L 396 135 L 387 135 Z" stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="4,4"/><text transform="translate(371 362.875) rotate(-90)" fill="red"><tspan font-family="Courier" font-size="12" font-weight="500" fill="red" x="45.16504" y="11" textLength="122.41992">process_exception</tspan></text><g id="id33_Graphic"><path d="M 144 405 L 505.4694 405 L 513 418.5 L 505.4694 432 L 144 432 L 153 418.5 Z" fill="white"/><path d="M 144 405 L 505.4694 405 L 513 418.5 L 505.4694 432 L 144 432 L 153 418.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(149 411.5)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" fill="black" x="144.81543" y="11" textLength="69.36914">view function</tspan></text></g></g></g></svg> diff --git a/docs/topics/http/middleware.txt b/docs/topics/http/middleware.txt index 16fdace825..1f5414e95b 100644 --- a/docs/topics/http/middleware.txt +++ b/docs/topics/http/middleware.txt @@ -16,18 +16,128 @@ how to write your own middleware. Django ships with some built-in middleware you can use right out of the box. They're documented in the :doc:`built-in middleware reference </ref/middleware>`. +.. versionchanged:: 1.10 + + A new style of middleware was introduced for use with the new + :setting:`MIDDLEWARE` setting. If you're using the old + :setting:`MIDDLEWARE_CLASSES` setting, you'll need to :ref:`adapt old, + custom middleware <upgrading-middleware>` before using the new setting. + This document describes new-style middleware. Refer to this page in older + versions of the documentation for a description of how old-style middleware + works. + +Writing your own middleware +=========================== + +A middleware factory is a callable that takes a ``get_response`` callable and +returns a middleware. A middleware is a callable that takes a request and +returns a response, just like a view. + +A middleware can be written as a function that looks like this:: + + def simple_middleware(get_response): + # One-time configuration and initialization. + + def middleware(request): + # Code to be executed for each request before + # the view is called. + + try: + response = get_response(request) + except Exception as e: + # Code to handle an exception that wasn't caught + # further up the chain, if desired. + ... + + # Code to be executed for each request/response after + # the view is called. + + return response + + return middleware + +Or it can be written as a class with a ``__call__()`` method, like this:: + + class SimpleMiddleware(object): + def __init__(self, get_response): + self.get_response = get_response + # One-time configuration and initialization. + + def __call__(self, request): + # Code to be executed for each request before + # the view is called. + + try: + response = self.get_response(request) + except Exception as e: + # Code to handle an exception that wasn't caught + # further up the chain, if desired. + ... + + # Code to be executed for each request/response after + # the view is called. + + return response + +In both examples, the ``try``/``except`` isn't required if the middleware +doesn't need to handle any exceptions. If it is included, it should probably +catch something more specific than ``Exception``. + +The ``get_response`` callable provided by Django might be the actual view (if +this is the last listed middleware) or it might be the next middleware in the +chain. The current middleware doesn't need to know or care what exactly it is, +just that it represents whatever comes next. + +The above is a slight simplification -- the ``get_response`` callable for the +last middleware in the chain won't be the actual view but rather a wrapper +method from the handler which takes care of applying :ref:`view middleware +<view-middleware>`, calling the view with appropriate URL arguments, and +applying :ref:`template-response <template-response-middleware>` middleware. + +Middleware can live anywhere on your Python path. + +``__init__(get_response)`` +-------------------------- + +Middleware classes must accept a ``get_response`` argument. You can also +initialize some global state for the middleware. Keep in mind a couple of +caveats: + +* Django initializes your middleware with only the ``get_response`` argument, + so you can't define ``__init__()`` as requiring any other arguments. + +* Unlike the ``__call__()`` method which get called once per request, + ``__init__()`` is called only *once*, when the Web server starts. + +.. versionchanged:: 1.10 + + In older versions, ``__init__`` was not called until the Web server + responded to its first request. + + If you want to allow your middleware to be used in Django 1.9 and earlier, + make ``get_response`` an optional argument (``get_response=None``). + +Marking middleware as unused +---------------------------- + +It's sometimes useful to determine at startup time whether a piece of +middleware should be used. In these cases, your middleware's ``__init__()`` +method may raise :exc:`~django.core.exceptions.MiddlewareNotUsed`. Django will +then remove that middleware from the middleware process and log a debug message +to the :ref:`django-request-logger` logger when :setting:`DEBUG` is ``True``. + Activating middleware ===================== -To activate a middleware component, add it to the -:setting:`MIDDLEWARE_CLASSES` list in your Django settings. +To activate a middleware component, add it to the :setting:`MIDDLEWARE` list in +your Django settings. -In :setting:`MIDDLEWARE_CLASSES`, each middleware component is represented by -a string: the full Python path to the middleware's class name. For example, +In :setting:`MIDDLEWARE`, each middleware component is represented by a string: +the full Python path to the middleware's class or function name. For example, here's the default value created by :djadmin:`django-admin startproject <startproject>`:: - MIDDLEWARE_CLASSES = [ + MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -37,13 +147,12 @@ here's the default value created by :djadmin:`django-admin startproject 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] -A Django installation doesn't require any middleware — -:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like — but it's strongly -suggested that you at least use +A Django installation doesn't require any middleware — :setting:`MIDDLEWARE` +can be empty, if you'd like — but it's strongly suggested that you at least use :class:`~django.middleware.common.CommonMiddleware`. -The order in :setting:`MIDDLEWARE_CLASSES` matters because a middleware can -depend on other middleware. For instance, +The order in :setting:`MIDDLEWARE` matters because a middleware can depend on +other middleware. For instance, :class:`~django.contrib.auth.middleware.AuthenticationMiddleware` stores the authenticated user in the session; therefore, it must run after :class:`~django.contrib.sessions.middleware.SessionMiddleware`. See @@ -54,55 +163,21 @@ Hooks and application order =========================== During the request phase, before calling the view, Django applies middleware -in the order it's defined in :setting:`MIDDLEWARE_CLASSES`, top-down. Two -hooks are available: - -* :meth:`process_request` -* :meth:`process_view` - -During the response phase, after calling the view, middleware are applied in -reverse order, from the bottom up. Three hooks are available: - -* :meth:`process_exception` (only if the view raised an exception) -* :meth:`process_template_response` (only for template responses) -* :meth:`process_response` +in the order it's defined in :setting:`MIDDLEWARE`, top-down. You can think of +it like an onion: each middleware class is a "layer" that wraps the view. -.. image:: _images/middleware.* - :alt: middleware application order - :width: 481 - :height: 409 +Middleware see only the changes made by middleware that run before it. A +middleware (and the view) is skipped entirely if a preceding middleware +short-circuits by returning a response without ever calling ``get_response``. +That response will only pass through the middleware that have already run. -If you prefer, you can also think of it like an onion: each middleware class -is a "layer" that wraps the view. - -The behavior of each hook is described below. - -Writing your own middleware -=========================== +Similarly, a middleware that sees the request on the way in and doesn't return +a response is guaranteed that it will always see the response on the way back +out. If the middleware also wants to see any uncaught exception on the way out, +it can wrap its call to ``get_response()`` in a ``try``/``except``. -Writing your own middleware is easy. Each middleware component is a single -Python class that defines one or more of the following methods: - -.. _request-middleware: - -``process_request()`` ---------------------- - -.. method:: process_request(request) - -``request`` is an :class:`~django.http.HttpRequest` object. - -``process_request()`` is called on each request, before Django decides which -view to execute. - -It should return either ``None`` or an :class:`~django.http.HttpResponse` -object. If it returns ``None``, Django will continue processing this request, -executing any other ``process_request()`` middleware, then, ``process_view()`` -middleware, and finally, the appropriate view. If it returns an -:class:`~django.http.HttpResponse` object, Django won't bother calling any -other request, view or exception middleware, or the appropriate view; it'll -apply response middleware to that :class:`~django.http.HttpResponse`, and -return the result. +Besides the middleware pattern described earlier, you can add two other methods +to class-based middleware: .. _view-middleware: @@ -125,14 +200,13 @@ It should return either ``None`` or an :class:`~django.http.HttpResponse` object. If it returns ``None``, Django will continue processing this request, executing any other ``process_view()`` middleware and, then, the appropriate view. If it returns an :class:`~django.http.HttpResponse` object, Django won't -bother calling any other view or exception middleware, or the appropriate -view; it'll apply response middleware to that -:class:`~django.http.HttpResponse`, and return the result. +bother calling the appropriate view; it'll apply response middleware to that +:class:`~django.http.HttpResponse` and return the result. .. note:: Accessing :attr:`request.POST <django.http.HttpRequest.POST>` inside - middleware from ``process_request`` or ``process_view`` will prevent any + middleware before the view runs or in ``process_view()`` will prevent any view running after the middleware from being able to :ref:`modify the upload handlers for the request <modifying_upload_handlers_on_the_fly>`, and should normally be avoided. @@ -170,41 +244,8 @@ called. Middleware are run in reverse order during the response phase, which includes ``process_template_response()``. -.. _response-middleware: - -``process_response()`` ----------------------- - -.. method:: process_response(request, response) - -``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is -the :class:`~django.http.HttpResponse` or -:class:`~django.http.StreamingHttpResponse` object returned by a Django view -or by a middleware. - -``process_response()`` is called on all responses before they're returned to -the browser. - -It must return an :class:`~django.http.HttpResponse` or -:class:`~django.http.StreamingHttpResponse` object. It could alter the given -``response``, or it could create and return a brand-new -:class:`~django.http.HttpResponse` or -:class:`~django.http.StreamingHttpResponse`. - -Unlike the ``process_request()`` and ``process_view()`` methods, the -``process_response()`` method is always called, even if the -``process_request()`` and ``process_view()`` methods of the same middleware -class were skipped (because an earlier middleware method returned an -:class:`~django.http.HttpResponse`). In particular, this means that your -``process_response()`` method cannot rely on setup done in -``process_request()``. - -Finally, remember that during the response phase, middleware are applied in -reverse order, from the bottom up. This means classes defined at the end of -:setting:`MIDDLEWARE_CLASSES` will be run first. - Dealing with streaming responses -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +================================ Unlike :class:`~django.http.HttpResponse`, :class:`~django.http.StreamingHttpResponse` does not have a ``content`` @@ -229,66 +270,62 @@ must test for streaming responses and adjust their behavior accordingly:: .. _exception-middleware: -``process_exception()`` ------------------------ +Exception middleware +==================== -.. method:: process_exception(request, exception) +A middleware that does some custom exception handling might looks like this:: -``request`` is an :class:`~django.http.HttpRequest` object. ``exception`` is an -``Exception`` object raised by the view function. + class ExceptionMiddleware(object): + def __init__(self, get_response): + self.get_response = get_response -Django calls ``process_exception()`` when a view raises an exception. -``process_exception()`` should return either ``None`` or an -:class:`~django.http.HttpResponse` object. If it returns an -:class:`~django.http.HttpResponse` object, the template response and response -middleware will be applied, and the resulting response returned to the -browser. Otherwise, default exception handling kicks in. + def __call__(self, request): + try: + response = self.get_response(request) + except Exception as e: + # Do something with the exception and possibly reraise it + # unless you wish to silence it. + ... + return response -Again, middleware are run in reverse order during the response phase, which -includes ``process_exception``. If an exception middleware returns a response, -the middleware classes above that middleware will not be called at all. +Middleware that wants to do something for all exception responses, an HTTP 404 +for example, need to both catch the appropriate exception (e.g. ``Http404``) +and look for regular responses with the status code of interest. You can +subclass :class:`~django.middleware.exception.ExceptionMiddleware` if you want +to transform exceptions into the appropriate response. -``__init__()`` --------------- +.. _upgrading-middleware: -Most middleware classes won't need an initializer since middleware classes are -essentially placeholders for the ``process_*`` methods. If you do need some -global state you may use ``__init__`` to set up. However, keep in mind a couple -of caveats: +Upgrading pre-Django 1.10-style middleware +========================================== -* Django initializes your middleware without any arguments, so you can't - define ``__init__`` as requiring any arguments. - -* Unlike the ``process_*`` methods which get called once per request, - ``__init__`` gets called only *once*, when the Web server starts. - -.. versionchanged:: 1.10 - - In older versions, ``__init__`` was not called until the Web server - responded to its first request. - -Marking middleware as unused -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. class:: django.utils.deprecation.MiddlewareMixin + :module: -It's sometimes useful to determine at run-time whether a piece of middleware -should be used. In these cases, your middleware's ``__init__`` method may -raise :exc:`django.core.exceptions.MiddlewareNotUsed`. Django will then remove -that piece of middleware from the middleware process and a debug message will -be logged to the ``django.request`` logger when :setting:`DEBUG` is set to -``True``. +Django provides ``django.utils.deprecation.MiddlewareMixin`` to ease providing +the existing built-in middleware in both new-style and old-style forms and to +ease similar conversions of third-party middleware. -Guidelines ----------- +In most cases, this mixin will be sufficient to convert a middleware with +sufficient backwards-compatibility; the new short-circuiting semantics will be +harmless or even beneficial to the existing middleware. -* Middleware classes don't have to subclass anything. +In a few cases, a middleware class may need more invasive changes to adjust to +the new semantics. -* The middleware class can live anywhere on your Python path. All Django - cares about is that the :setting:`MIDDLEWARE_CLASSES` setting includes - the path to it. +For example, in the current request-handling logic, the handler transforms any +exception that passes through all ``process_exception`` middleware uncaught +into a response with appropriate status code (e.g. 404, 403, 400, or 500), and +then passes that response through the full chain of ``process_response`` +middleware. -* Feel free to look at :doc:`Django's available middleware - </ref/middleware>` for examples. +In new-style middleware, a given middleware only gets one shot at a given +response or uncaught exception "on the way out," and will see either a returned +response or an uncaught exception, but not both. -* If you write a middleware component that you think would be useful to - other people, contribute to the community! :doc:`Let us know - </internals/contributing/index>`, and we'll consider adding it to Django. +This means that certain middleware which want to do something with all 404 +responses (for example, the ``RedirectFallbackMiddleware`` and +``FlatpageFallbackMiddleware`` in ``django.contrib.redirects`` and +``django.contrib.flatpages``) now need to watch out for both a 404 response +and an uncaught ``Http404`` exception. They do this by subclassing +:class:`~django.middleware.exception.ExceptionMiddleware`. diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt index 34a1b28b73..1a948397ae 100644 --- a/docs/topics/http/sessions.txt +++ b/docs/topics/http/sessions.txt @@ -18,13 +18,13 @@ Sessions are implemented via a piece of :doc:`middleware </ref/middleware>`. To enable session functionality, do the following: -* Edit the :setting:`MIDDLEWARE_CLASSES` setting and make sure - it contains ``'django.contrib.sessions.middleware.SessionMiddleware'``. - The default ``settings.py`` created by ``django-admin startproject`` - has ``SessionMiddleware`` activated. +* Edit the :setting:`MIDDLEWARE` setting and make sure it contains + ``'django.contrib.sessions.middleware.SessionMiddleware'``. The default + ``settings.py`` created by ``django-admin startproject`` has + ``SessionMiddleware`` activated. If you don't want to use sessions, you might as well remove the -``SessionMiddleware`` line from :setting:`MIDDLEWARE_CLASSES` and +``SessionMiddleware`` line from :setting:`MIDDLEWARE` and ``'django.contrib.sessions'`` from your :setting:`INSTALLED_APPS`. It'll save you a small bit of overhead. diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt index 81dc4a0d94..ae5b714726 100644 --- a/docs/topics/http/urls.txt +++ b/docs/topics/http/urls.txt @@ -41,8 +41,8 @@ algorithm the system follows to determine which Python code to execute: 1. Django determines the root URLconf module to use. Ordinarily, this is the value of the :setting:`ROOT_URLCONF` setting, but if the incoming ``HttpRequest`` object has a :attr:`~django.http.HttpRequest.urlconf` - attribute (set by middleware :ref:`request processing <request-middleware>`), - its value will be used in place of the :setting:`ROOT_URLCONF` setting. + attribute (set by middleware), its value will be used in place of the + :setting:`ROOT_URLCONF` setting. 2. Django loads that Python module and looks for the variable ``urlpatterns``. This should be a Python list of :func:`django.conf.urls.url` diff --git a/docs/topics/i18n/timezones.txt b/docs/topics/i18n/timezones.txt index 8ea63f2908..674edc1a19 100644 --- a/docs/topics/i18n/timezones.txt +++ b/docs/topics/i18n/timezones.txt @@ -175,13 +175,14 @@ the most likely choices. Here's an example that stores the current timezone in the session. (It skips error handling entirely for the sake of simplicity.) -Add the following middleware to :setting:`MIDDLEWARE_CLASSES`:: +Add the following middleware to :setting:`MIDDLEWARE`:: import pytz from django.utils import timezone + from django.django.utils.deprecation import MiddlewareMixin - class TimezoneMiddleware(object): + class TimezoneMiddleware(MiddlewareMixin): def process_request(self, request): tzname = request.session.get('django_timezone') if tzname: diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt index 43184a13a1..3f13021bc8 100644 --- a/docs/topics/i18n/translation.txt +++ b/docs/topics/i18n/translation.txt @@ -38,7 +38,7 @@ make some optimizations so as not to load the internationalization machinery. .. note:: Make sure you've activated translation for your project (the fastest way is - to check if :setting:`MIDDLEWARE_CLASSES` includes + to check if :setting:`MIDDLEWARE` includes :mod:`django.middleware.locale.LocaleMiddleware`). If you haven't yet, see :ref:`how-django-discovers-language-preference`. @@ -1422,7 +1422,7 @@ Django provides two mechanisms to internationalize URL patterns: Using either one of these features requires that an active language be set for each request; in other words, you need to have :class:`django.middleware.locale.LocaleMiddleware` in your - :setting:`MIDDLEWARE_CLASSES` setting. + :setting:`MIDDLEWARE` setting. Language prefix in URL patterns ------------------------------- @@ -2065,8 +2065,8 @@ prefer, then you also need to use the ``LocaleMiddleware``. It customizes content for each user. To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'`` -to your :setting:`MIDDLEWARE_CLASSES` setting. Because middleware order -matters, you should follow these guidelines: +to your :setting:`MIDDLEWARE` setting. Because middleware order matters, follow +these guidelines: * Make sure it's one of the first middlewares installed. * It should come after ``SessionMiddleware``, because ``LocaleMiddleware`` @@ -2075,9 +2075,9 @@ matters, you should follow these guidelines: to resolve the requested URL. * If you use ``CacheMiddleware``, put ``LocaleMiddleware`` after it. -For example, your :setting:`MIDDLEWARE_CLASSES` might look like this:: +For example, your :setting:`MIDDLEWARE` might look like this:: - MIDDLEWARE_CLASSES = [ + MIDDLEWARE = [ 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', diff --git a/docs/topics/testing/tools.txt b/docs/topics/testing/tools.txt index 8db06c15a3..d2ef214c36 100644 --- a/docs/topics/testing/tools.txt +++ b/docs/topics/testing/tools.txt @@ -1182,7 +1182,7 @@ easy:: class MiddlewareTestCase(TestCase): def test_cache_middleware(self): - with self.modify_settings(MIDDLEWARE_CLASSES={ + with self.modify_settings(MIDDLEWARE={ 'append': 'django.middleware.cache.FetchFromCacheMiddleware', 'prepend': 'django.middleware.cache.UpdateCacheMiddleware', 'remove': [ @@ -1233,7 +1233,7 @@ decorator:: class MiddlewareTestCase(TestCase): - @modify_settings(MIDDLEWARE_CLASSES={ + @modify_settings(MIDDLEWARE={ 'append': 'django.middleware.cache.FetchFromCacheMiddleware', 'prepend': 'django.middleware.cache.UpdateCacheMiddleware', }) @@ -1245,7 +1245,7 @@ The decorator can also be applied to test case classes:: from django.test import TestCase, modify_settings - @modify_settings(MIDDLEWARE_CLASSES={ + @modify_settings(MIDDLEWARE={ 'append': 'django.middleware.cache.FetchFromCacheMiddleware', 'prepend': 'django.middleware.cache.UpdateCacheMiddleware', }) |
