1
kellyl 2015-05-19 17:28:43 +08:00
@cc7756789,如果你想得到大家的帮助,首先要把问题内容格式整理好。V2EX支持markdown语法。
建议问题标题修改为「django视图类继承DetailView和TemplateView后报错」,你的问题代码可以格式化如下 <pre> class Links(TemplateView): _____template_name = "home/links.html" _____def get_context_data(self, **kwargs): __________context = super(Links, self).get_context_data(**kwargs) __________context['link'] = Friend_Links.objects.all() __________context['latest_article_list'] = latest_article_list __________context['now'] = time.strftime('%Y-%m-%d %X', time.localtime()) __________context['ip'] = self.request.META['REMOTE_ADDR'] __________return context class Detail(DetailView, Links): _____model = Article _____context_object_name = "ar" _____template_name = "home/detail.html" _____def get_context_data(self, **kwargs): __________context = super(Detail, self).get_context_data(**kwargs) __________context['latest_article_list'] = latest_article_list __________context['now'] = time.strftime('%Y-%m-%d %X', time.localtime()) _____return context </pre> 这是典型的多重继承方法属性读取顺序问题。在Python里叫"Method Resolution Order",Python的继承多重继承机制请看参考阅读(如果经常写Python面向对象的代码,一定要弄明白多重继承中C3线性继承的使用)。 我们来看一下Detail类的MRO。 >>> Detail.__mro__ ....(Detail, .... django.views.generic.detail.DetailView, .... django.views.generic.detail.SingleObjectTemplateResponseMixin, .... gizwits_developer.views.Links, .... django.views.generic.base.TemplateView, .... django.views.generic.base.TemplateResponseMixin, .... django.views.generic.detail.BaseDetailView, .... django.views.generic.detail.SingleObjectMixin, .... django.views.generic.base.ContextMixin, .... django.views.generic.base.View, .... object) 当页面打开Detail页面时,发生了: 1. django调用视图的self.get方法 2. 根据mro找到django.views.generic.base.TemplateView.get方法,在get方法中调用self.get_context_data(**kwargs) 3. 根据mro,分别调用Detail, DetailView...中的get_context_data,当调用到django.views.generic.detail.SingleObjectMixin.get_context_data时,代码读取`self.object`,但是此时self中没有`object`属性,页面报错。因为`self.obejct`的赋值是在`django.views.generic.detail.BaseDetailView.get`做的,但是get方法被`django.views.generic.base.TemplateView.get`拦截了,导致执行不到。 如何解决(方法很多,这里简单列出两个面向对象的方法实现): 1. 调整__mro__中get的顺序。不建议。因为复杂的mro并不能够简单通过Detail(Links,DetailView)改为Detail(DetailView, Links)能够掉整的;在Detail类复写get也能够解决,但后期代码难维护。 2. 将TemplateView在__mro__中移除。这是我个人建议的方法。其实问题产生的原因是Links和DetailView都是TemplateResponseMixin的子类,交叉继承导致的。DetailView本来就有TemplateView的功能,再次继承的话容易出问题。 解决方法(使用复用的contextMixin类): <pre> class LinksContext(ContextMixin): _____def get_context_data(self, **kwargs): __________context = super(LinksContext, self).get_context_data(**kwargs) __________context['link'] = Friend_Links.objects.all() __________context['latest_article_list'] = latest_article_list __________context['now'] = time.strftime('%Y-%m-%d %X', time.localtime()) __________context['ip'] = self.request.META['REMOTE_ADDR'] __________return context class Links(TemplateView, LinksContext): _____template_name = "home/links.html" class Detail(DetailView, LinksContext): _____model = Article _____context_object_name = "ar" _____template_name = "home/detail.html" _____def get_context_data(self, **kwargs): __________context = super(Detail, self).get_context_data(**kwargs) __________context['latest_article_list'] = latest_article_list __________context['now'] = time.strftime('%Y-%m-%d %X', time.localtime()) _____return context <pre> 参考阅读: http://python-history.blogspot.com/2010/06/method-resolution-order.html https://www.python.org/download/releases/2.3/mro |