[PYTHON] Add the original context_processor

This article is the 25th day article of Django 2016 Advent Calendar.

I'm sorry for the basics on the last day, but since I have never added it myself, I will write about studying and implementing context_processors.

No, Python 3.6 is out!

** What is written in this article **: How to add context_processors, implementation example ** What I'm writing in this article **: Behavior inside context_processors

Trigger

At the moment, the site I'm developing is completely responsive to writing templates, but now I need to separate some of the templates for mobile and PC.

So I tried to use django-mobile, but it wasn't yet compatible with Django 1.10. There was also a way to handle it by issuing a pull request by myself, but I didn't have much time and I didn't have to do that difficult, so I decided to implement it myself quickly. I've never used context_processors, so I started by reading the document. It was really easy.

django-mobile also has middleware, but I didn't need it this time, so I studied only context_processors.

What is context_processors?

It allows you to use variables on the template without having to pass them directly from the view.

Implementation

By default, the TEMPLATES in settings.py will (probably) look like this:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Below is the contents of django / templates / context_processors.py. Since it is long, I omit it in the middle.

django/templates/context_processors.py



"""
A set of request processors that return dictionaries to be merged into a
template context. Each function takes the request object as its only parameter
and returns a dictionary to add to the context.

These are referenced from the 'context_processors' option of the configuration
of a DjangoTemplates backend and used by RequestContext.
"""

from __future__ import unicode_literals

import itertools

from django.conf import settings
from django.middleware.csrf import get_token
from django.utils.encoding import smart_text
from django.utils.functional import SimpleLazyObject, lazy


def csrf(request):
    """
    Context processor that provides a CSRF token, or the string 'NOTPROVIDED' if
    it has not been provided by either a view decorator or the middleware
    """
    def _get_val():
        token = get_token(request)
        if token is None:
            # In order to be able to provide debugging info in the
            # case of misconfiguration, we use a sentinel value
            # instead of returning an empty dict.
            return 'NOTPROVIDED'
        else:
            return smart_text(token)

    return {'csrf_token': SimpleLazyObject(_get_val)}

"""
Omitted on the way
"""

def request(request):
    return {'request': request}

If you specify the path of the function in context_processors of TEMPLATES above, you can call the function in the template and use the return value in the template. You don't have to explicitly pass it from view to template.

It should be noted here that even if you create a function called hoge with context_processors, you cannot call hoge with template. Just like when you pass a variable from view to template, you can specify the variable and contents with the name you want with dict and return it, and you can refer to the key of that dict with template. Therefore, when the following function hoge is included in context_processors, fuga is referenced on the template and the string fugafuga can be used on the template.

Definition

def hoge(request):
    return {"fuga": "fugafuga"}

reference

{{ fuga }}

Therefore, for csrf provided by default, you will call csrf_token as in django / templates / context_processors.py instead of csrf.

{% csrf_token %}

Caution

The above settings.py does not load 'django.template.context_processors.csrf',, but csrf is treated specially and is set to be loaded by default in the following locations.

django/template/context.py



# Hard-coded processor for easier use of CSRF protection.
_builtin_context_processors = ('django.template.context_processors.csrf',)

django/template/engine.py


class Engine(object):
    """
abridgement
    """

    @cached_property
    def template_context_processors(self):
        context_processors = _builtin_context_processors
        context_processors += tuple(self.context_processors)
        return tuple(import_string(path) for path in context_processors)
    """
abridgement
    """

Try to implement it yourself

As I wrote at the beginning, I want to do something similar to django-mobile, so I will add a context_processor that determines whether it is a smartphone from the user agent information included in the request and returns True or False.

The ones I made are as follows. Mecha is easy w

app/context_processors.py



import re
MOBILE_REGEXP = re.compile(r"Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone|IEMobile|Opera Mini|WILLCOM")

def is_mobile(request):
    is_mobile = False
    if MOBILE_REGEXP.search(request.META['HTTP_USER_AGENT']) is not None:
        is_mobile = True
    return {"is_mobile": is_mobile}

Add ʻapp.context_processors.is_mobile to context_processors` in TEMPLATES.

settings.py


TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'app.context_processors.is_mobile',  #this
            ],
        },
    },
]

And use it in the following way.

{% if is_mobile == True %}
<p>Access from mobile</p>
{% else %}
<p>Access from PC</p>
{% endif %}

Summary

I found it very easy to add context_processor. I only investigated how to implement it, so if I have time, I would like to study the internal operation properly.

Finally

I was very surprised that I didn't expect Django's Advent calendar to fill up this far. Many people were in charge of multiple days, and thank you very much!

I myself still had a lot of basic posts at the beginner level, so I hope I can write something a little higher level this time next year! (It's not good for the company to develop it crunchy ...!)

Next year, I hope Django will be more exciting in Japan than this year, and I would like to conclude the last day of the Advent calendar. Everyone, enjoy Christmas! !! (Hematemesis) & Have a good year! !! !!

Recommended Posts

Add the original context_processor
Preparing to load the original dataset
Run the original YOLO with Jetson Nano
In Jupyter, add IPerl to the kernel.
Add a layer using the Keras backend
Add lines and text on the image