Могу ли я создать микширование Django, которое добавляет контекстные переменные непосредственно перед рендерингом шаблона?

#django #django-views

#django #django-views

Вопрос:

У меня есть приложение Django, которое использует JSON API в качестве источника данных.

Вот упрощенный пример использования в одном из моих views.py :

 class GroupsList(LoginRequiredMixin):
    
    def get(self, request, **kwargs):

        # Get file list and totals
        try:
            group_list = group_adapter.list() # makes an API call and ALSO populates a meta info class
        except APIAccessForbidden:
            return HttpResponseRedirect(reverse('logout'))
    
        return render(request, 'groups/index.html', {
            # can I make a mixin to add data here gained from the API call?
            'group_list': group_list,         
        })
 

Эта строка:

group_adapter.list() Вызов помещает некоторую метаинформацию в другой класс, который не связан с самим group_list . Я хотел бы передать эти данные в шаблон. Обычно я бы использовал a context_processor , но при вызове контекстного процессора вызов API еще не был выполнен. Я мог бы вручную проверить информацию и добавить ее в render() метод, но тогда мне нужно было бы сделать это в десятках разных представлений.

Потенциальное решение № 1: создайте для него микширование

Могу ли я использовать здесь микширование, которое добавляет эту информацию в контекст ПОСЛЕ запуска кода представления, но ДО того, как рендеринг передаст информацию в шаблон?

Другими словами, есть ли способ сделать это:

 class GroupsList(LoginRequiredMixin, AddMetaInfoToContextMixin):
 

а затем создайте микширование примерно так?

 class AddMetaInfoToContextMixin(ContextMixin):

    def get_context_data(self, **kwargs):
        # self.request
        context = super().get_context_data(**kwargs)
        context['global_meta_information'] = get_global_meta_information()
        return context
 

Потенциальное решение № 2: создайте переопределенный templateview

Комментатор Melvyn указал, что я потенциально могу подкласс TemplateView и переопределить get_context_data() , так будет ли что-то вроде этого работать?

 class TemplateViewWithMeta(TemplateView):

    def get_context_data(self, *args, **kwargs):
        context = super(Home. self).get_context_data(*args, **kwargs)
        context['global_meta_information'] = get_global_meta_information()
        return context

class GroupsList(LoginRequiredMixin, TemplateViewWithMeta):
    [...]
 

Комментарии:

1. Я не понимаю этот дизайн. Вы заполняете синглтон метаинформацией при вызове API? Почему бы не вернуть это? И вы говорите, что это должно быть сделано после запуска представления, но до рендеринга шаблона, что противоречит. В любом случае, любой подкласс TemplateView has get_context_data , который вызывается раньше render_to_response .

2. Спасибо за ответ. Вы правы, что я «заполняю синглтон метаинформацией» при вызове API. Что касается «почему бы не вернуть это», это потому, что это информация о лицензировании для приложения, которую нужно было закрепить после факта. Я бы хотел, чтобы мне не нужно было загрязнять каждое отдельное представление кодом обработки для него. Похоже, я могу подкласс TemplateView и обрабатывать эту логику в переопределенном get_context_data?

Ответ №1:

Типичный рабочий процесс для общего шаблона Django TemplateView:

  • get()
    • get_context_data()
      • render_to_response()

Итак, в вашем случае, следуя духу общих представлений, вы могли бы сделать это следующим образом:

 from django.views import generic

class BaseRemoteApiView(generic.TemplateView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.group_list = None

    def get(self, request, *args, **kwargs):
        try:
            self.group_list = group_adapter.list() # makes an API call and ALSO populates a meta info class
        except APIAccessForbidden:
            return HttpResponseRedirect(reverse('logout'))

        return super().get(request, *args, **kwargs)

class RemoteApiContextMixin(generic.base.ContextMixin):
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["group_list"] = self.group_list
        context["meta_information"] = get_global_meta_information()
        return context

class ConcreteRemoteApiView(RemoteApiContextMixin, BaseRemoteApiView):
    pass
 

Конечно, вам не нужно создавать 3 класса и вы можете просто объединить 3 в один — зависит от того, насколько смешиваемым вы хотите быть.

Комментарии:

1. Прежде всего, спасибо, что нашли время, чтобы напечатать это.

2. Итак, все, что мне действительно нужно для микширования, это ДОБАВИТЬ глобальную мета-информацию, мне не нужно добавлять материал group_list, который я могу делать во всех отдельных представлениях. Итак, я создал StoreLicenseMixin(ContentMixin) класс и добавил глобальную мету к информации и вернул контекст, но я не вижу этих данных в своем шаблоне.

3. Я обновил свое доказательство концепции «микширования» выше. Это в основном то, что я делаю, и у меня все еще нет этих данных, доступных в шаблоне.

4. Когда создаются эти данные? Если он создан в промежуточном программном обеспечении при выходе ответа, то представление никогда не сможет получить информацию. если он создан за пределами какого-либо другого процесса после завершения просмотра — та же проблема. Рендеринг является частью кода представления, вы не можете его разделить — по крайней мере, без изменения / обхода архитектуры ядра Django.

5. «Итак, все, что мне действительно нужно для микширования, это ДОБАВИТЬ глобальную мета-информацию, мне не нужно добавлять материал group_list, который я могу делать во всех отдельных представлениях». — Ну, вы говорите, что мета-информация создается при вызове API. Во-вторых, вы хотите выйти из системы пользователя по ошибке с перенаправлением. Итак, вы уже подключены к списку групп, и неразумно его разделять. Все еще непонятно, что оно не попадает в шаблон, если только у вас нет опечатки / ошибки в вашем шаблоне.