How do I inject the same context into many different Django views?

I want to put information about one object in many views without repeating it in get_context_data in every view. Since I understand that I need a class with get_context_data inside, I can mix with other views. Here in my example I want to see "some_object" in the 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 part of the parent class "View". Maybe I need a more special class for inheritance in BaseObjectInfoView?

or maybe it's better to build the context with a different method?

0


source to share


2 answers


Mixins don't have to be views, but it helps the IDE if they have methods that they override.

The contexts are handled with django.views.generic.base.ContextMixin

(more on this very handy site ). So the cool views on 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 a lot of projects and the simple views you have to create anyway are completely declarative. And just, I mean they can be made up of mulitple mixins, all of which do the heavy lifting in get_queryset, get_context_data, or form_valid. A more complex example, straight from the 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

      

0


source


Perhaps 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

      

0


source







All Articles