middleware.py

Middleware installation

The built-in middleware is compatible both to the old type of middleware and to the new type of middleware.

To add the built-in middleware to the project settings.py, define DJK_MIDDLEWARE value, then add it to the MIDDLEWARE list:

DJK_MIDDLEWARE = 'django_jinja_knockout.middleware.ContextMiddleware'

MIDDLEWARE = [
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    DJK_MIDDLEWARE,
]

The built-in middleware is applied only to Django apps which are registered in settings.py variable DJK_APPS list:

DJK_APPS = (
    'djk_sample',
    'club_app',
    'event_app',
)

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites',
    'django_jinja',
    'django_jinja.contrib._humanize',
    'djk_ui',
    'django_jinja_knockout',
) + DJK_APPS

Such apps has to be both in DJK_APPS list and in INSTALLED_APPS list. See sample settings.py for the complete example.

Since v0.9.0 the dependency on DJK_MIDDLEWARE was sufficiently reduced. The code which does not call DjkAppConfig class .get_context_middleware() method and does not use middleware features described here (like permission checks), should work without DJK_MIDDLEWARE defined in settings.py at all. However beware that RendererModelForm and ForeignKeyGridWidget still require it, so it’s not the recommended settings to run.

Extending built-in middleware

Middleware is extendable (inheritable), which allows to implement your own features by overloading it’s methods. See the example of extending middleware.

DjkAppConfig class .get_context_middleware() method should be used to resolve the installed ContextMiddleware class instead of direct import. Such way the extended ContextMiddleware class specified in settings.py DJK_MIDDLEWARE will be used instead of the original version:

from django_jinja_knockout.apps import DjkAppConfig

ContextMiddleware = DjkAppConfig.get_context_middleware()

Direct import from django_jinja_knockout.middleware or from my_project.middleware is possible but is discouraged as wrong version of middleware may be used.

The instance of middleware provides the access to current HTTP request instance anywhere in form / formset / field widget code:

request = ContextMiddleware.get_request()
  • Real HTTP request instance will be loaded when running as web server.
  • Fake request will be created when running in console (for example in the management commands). Fake request HTTP GET / POST arguments can be initialized via ContextMiddleware class .mock_request() method, before calling .get_request().

Still it’s wise to restrict .get_request() usage to forms / formsets / widgets mostly, avoiding usage at the model / database / console management command level, although the mocking requests makes that possible.

Automatic timezone detection

Automatic timezone detection and activation from the browser, which should be faster than using maxmind geoip database. It’s possible to get timezone name string from current browser http request to use in the application (for example to pass it to celery task):

ContextMiddleware.get_request_timezone()

Middleware security

The views that belong to modules defined in DJK_APPS are checked for permissions, specified in urls.py url() call kwargs.

DJK_APPS views are secured by the middleware with urls that deny access to anonymous / inactive users by default. Anonymous views require explicit permission defined as url() extra kwargs per each view in urls.py:

from my_app.views import signup
# ...
url(r'^signup/$', signup, name='signup', kwargs={'allow_anonymous': True})

Optional check for specific Django permission:

from my_app.views import check_project
# ...
url(r'^check-project/$', check_project, name='check_project', kwargs={
    'permission_required': 'my_app.project_can_add'
})

Request mock-up

It’s possible to mock-up requests in console mode (management commands) to resolve reverse URLs fully qualified names:

from django_jinja_knockout.apps import DjkAppConfig
from django_jinja_knockout import tpl

request = DjkAppConfig.get_context_middleware().get_request()
# Will return fully-qualified URL for the specified route with query string appended:
tpl.reverseq('profile_detail', kwargs={'profile_id': 1}, request=request, query={'users': [1,2,3]})

By default domain name is taken from current configured Django site. Otherwise either settings. DOMAIN_NAME or settings. ALLOWED_HOSTS should be set to autodetect current domain name.

Mini-router

Inherited middleware classes (see DJK_MIDDLEWARE settings) support built-in mini router, which could be used to implement CBV-like logic in the middleware class itself, either via request path string match or via the regexp match:

class ContextMiddleware(RouterMiddleware):

    routes_str = {
        '/-djk-js-error-/': 'log_js_error',
    }
    routes_re = [
        # (r'^/-djk-js-(?P<action>/?\w*)-/', 'log_js_error'),
    ]

    def log_js_error(self, **kwargs):
        from .log import send_admin_mail_delay
        vms = vm_list()
        # ... skipped ...
        return JsonResponse(vms)

Our request

Only views that belong to settings.py DJK_APPS (see Middleware installation) will be processed by djk middleware. One should override is_our_module() method in the extended middleware (see Extending built-in middleware) to implement custom middleware applying filter. The views, which have djk middleware applied, will have request object is_djk attribute set.