Как передать общие данные во все шаблоны в веб-фреймворках Django и Flask

Ответ

Чтобы избежать дублирования кода и не передавать одни и те же данные (например, имя сайта, меню навигации, информацию о пользователе) из каждой view-функции, в веб-фреймворках используются контекстные процессоры.

Контекстный процессор — это функция, которая принимает объект запроса и возвращает словарь. Этот словарь автоматически добавляется в контекст всех шаблонов.

Django

  1. Создайте функцию контекстного процессора. Обычно её размещают в файле context_processors.py внутри вашего приложения.

    # myapp/context_processors.py
    def project_context(request):
        return {
            'SITE_NAME': 'My Awesome Project',
            'SITE_VERSION': '1.0.2'
        }
  2. Зарегистрируйте его в settings.py.

    # 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',
                    # Добавляем наш процессор
                    'myapp.context_processors.project_context',
                ],
            },
        },
    ]

    Теперь переменные {{ SITE_NAME }} и {{ SITE_VERSION }} доступны в любом шаблоне проекта.

Flask

Во Flask для этой же цели используется декоратор @app.context_processor.

from flask import Flask

app = Flask(__name__)

@app.context_processor
def inject_global_data():
    # Словарь, который вернет эта функция, будет доступен во всех шаблонах
    return {
        'SITE_NAME': 'My Awesome Flask App'
    }

@app.route('/')
def index():
    # В шаблоне index.html можно использовать {{ SITE_NAME }}
    return render_template('index.html')

Ответ 18+ 🔞

Вот смотри, блядь, как в вебе делают, чтобы не пиздовать одно и то же в каждой функции. Представь, тебе на каждой странице надо имя сайта, менюшку, данные юзера тащить. Так вот, чтобы не превращаться в обезьяну с гранатой и не копипастить этот пиздец повсюду, умные дядьки придумали контекстные процессоры.

Это, сука, такая функция, которая хватает объект запроса и выплевывает словарь. А этот словарь потом автоматом лезет в контекст ВСЕХ шаблонов. Красота, ёпта!

В Django, например

  1. Делаешь функцию. Кидаешь её обычно в context_processors.py внутри своего приложения.

    # myapp/context_processors.py
    def project_context(request):
        return {
            'SITE_NAME': 'My Awesome Project',
            'SITE_VERSION': '1.0.2'
        }
  2. Прописываешь её в настройках, блядь. В settings.py её надо впихнуть в список.

    # 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',
                    # А вот сюда нашу подключаем, сука!
                    'myapp.context_processors.project_context',
                ],
            },
        },
    ]

    И всё, пиздец! Теперь в любом шаблоне можно писать {{ SITE_NAME }} и {{ SITE_VERSION }}, и они будут как родные.

А во Flask, блядь, ещё проще

Там для этого дела есть декоратор @app.context_processor. Вообще, мартышлюшка удобная.

from flask import Flask

app = Flask(__name__)

@app.context_processor
def inject_global_data():
    # Вот этот словарик и разлетится по всем шаблонам
    return {
        'SITE_NAME': 'My Awesome Flask App'
    }

@app.route('/')
def index():
    # И в index.html спокойно юзаешь {{ SITE_NAME }}, нихуя не передавая
    return render_template('index.html')

Вот и вся магия, ебать мои старые костыли. Не надо больше из каждой view, как сумасшедший, тащить одни и те же данные. Красота, в рот меня чих-пых!