【问题标题】:How to inject same context in many different Django views?如何在许多不同的 Django 视图中注入相同的上下文?
【发布时间】:2017-11-28 01:54:07
【问题描述】:

我想将一个对象的信息放在多个视图中,而不在每个视图的 get_context_data 中重复。如您所知,我需要一个内部带有 get_context_data 的类,我可以与其他视图混合使用。 在我的示例中,我想在 UpdateAnotherObjectView 的上下文中查看“some_object”:

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

它有效,但 get_context_data 不是父“视图”类的一部分。可能我需要更多特殊的类来继承 BaseObjectInfoView 吗?

或者用另一种方法构建上下文可能更好?

【问题讨论】:

    标签: django mixins


    【解决方案1】:

    Mixins 不需要是视图,但如果它们具有它们要覆盖的方法,它会对 IDE 有所帮助。

    上下文由django.views.generic.base.ContextMixin处理(详见this very handy site),所以基于类的视图方式是这样的:

    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
    

    我对许多项目都这样做,无论如何您必须创建的简单视图都是完全声明性的。简单来说,我的意思是它们可以由多个 mixin 组成,所有这些都在 get_queryset、get_context_data 或 form_valid 中完成困难的工作。更详细的示例,直接来自项目:

    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
    

    【讨论】:

    • 非常好!但是,如果我需要在上下文中放置一些依赖于视图 kwargs 的对象,如 url 模式(例如'object_pk')中提到的,我该如何使用上下文混合进行管理?在我的示例中,我通过 pk=1 获取对象,但 pk mast 取自 url。
    • 该pk在self.kwargs查看。这是由View.as_view() 完成的。但是SingleObjectMixinDetailView 的一部分,如果它是视图的主要对象,它将为您完成所有艰苦的工作。
    【解决方案2】:

    也许这种方式更容易阅读……

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-05
      • 1970-01-01
      • 1970-01-01
      • 2014-08-08
      • 2020-07-06
      • 2020-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多