How to inject same context in many different Django views?

不羁的心 提交于 2019-12-01 07:52:01

问题


I want to put info about one object in many views without repeating it in get_context_data in each view. As u understand i need a class with get_context_data inside, that i can mix with other views. Here in my example i want to see 'some_object' in context of UpdateAnotherObjectView:

class BaseObjectInfoView(View):
    def get_context_data(self, **kwargs):
        context_data = super(BaseObjectInfoView, self).get_context_data(**kwargs)
        context_data['some_object'] = SomeObjects.objects.get(pk=1)
        return context_data

class UpdateAnotherObjectView(BaseObjectInfo, UpdateView):
    template_name = 'create_object.html'
    form_class = AnotherObjectForm
    model = AnotherObjects

    def get_context_data(self, **kwargs):
        context_data = super(UpdateAnotherObjectView, self).get_context_data(**kwargs)
        context_data['all_another_objects'] = AnotherObjects.objects.all()
        return context_data

it works, but get_context_data is not a part of parent 'View' class. May be i need more special class to inherit from in BaseObjectInfoView?

or maybe better to construct context with another method ?


回答1:


Mixins don't need to be views, but it helps IDE's if they have the methods they're overriding.

Contexts are handled by django.views.generic.base.ContextMixin (details on this very handy site), So the class-based views way of things would be this:

from django.views import generic

class WebsiteCommonMixin(generic.base.ContextMixin):
    page_title = ''
    active_menu = None

    def get_context_data(self, **kwargs):
        context = super(WebsiteCommonMixin, self).get_context_data(**kwargs)
        context.update(dict(page_title=self.page_title, active_menu=self.active_menu))
        return context

class NewsListView(WebsiteCommonMixin, ListView):
    page_title = 'News list'
    active_menu = 'News'
    model = News
    paginate_by = 12

I do this for many projects and the simple views you have to create anyway, are fully declarative. And by simple, I mean that they can consist of mulitple mixins, all doing the hard stuff in either get_queryset, get_context_data or form_valid. More elaborate example, straight from a project:

class FeedbackMixin(object):
    message = 'Well Done!'

    def __init__(self):
        self._message_kwargs = {}
        super().__init__()

    def add_message_kwarg(self, name, value) -> None:
        self._message_kwargs[name] = value

    def format_message(self, kwargs) -> str:
        return self.message.format(**kwargs)

    def generate_message(self) -> None:
        msg = self.format_message(self._message_kwargs)
        messages.success(getattr(self, 'request'), msg)


class ModelFeedbackMixin(FeedbackMixin, generic.edit.ModelFormMixin):
    success_view_name = None
    success_url_kwargs = None

    def get_success_url_kwargs(self):
        return self.success_url_kwargs

    def get_success_url(self) -> str:
        success_url_kwargs = self.get_success_url_kwargs()
        if not self.success_view_name:
            url = super().get_success_url()
        elif success_url_kwargs is not None:
            url = reverse(self.success_view_name, kwargs=success_url_kwargs)
        else:
            if hasattr(self.object, 'slug'):
                url_kwargs = {'slug': self.object.slug}
            else:
                url_kwargs = {'pk': self.object.pk}
            url = reverse(self.success_view_name, kwargs=url_kwargs)
        return url

    def form_valid(self, form):
        response = super().form_valid(form)
        self.generate_message()
        return response



回答2:


Maybe this way could be easier to read...

def add_context(func):
# this is a wrapper function
    def wrapper(*args, **kwargs):
        context_data = func(*args, **kwargs)
        context_data['some_object'] = SomeObjects.objects.get(pk=1)
        return context_data
return wrapper


class UpdateAnotherObjectView(BaseObjectInfo, UpdateView):
    template_name = 'create_object.html'
    form_class = AnotherObjectForm
    model = AnotherObjects

    @add_context
    def get_context_data(self, **kwargs):
        kwargs['all_another_objects'] = AnotherObjects.objects.all()
        return kwargs


来源:https://stackoverflow.com/questions/44739145/how-to-inject-same-context-in-many-different-django-views

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!