Django中基于Mixin继承TemplateView实现视图复用是否有隐患?
Django视图子类化的可行性与问题分析
你当前的两个Listing视图存在明显代码重复,子类化确实是符合DRY原则的解决方案,但你提出的基类实现存在致命问题,直接运行会报错,下面具体分析:
原视图代码
class MyGiverView(LoginRequiredMixin, TemplateView): template_name = "generic_listings.html" message = "" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["list_of_stuff"] = MyModel.objects.filter( giver=self.request.user, status=1, ) context["message"] = self.message return context class MyTakerView(LoginRequiredMixin, TemplateView): template_name = "generic_listings.html" message = "" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["list_of_stuff"] = MyModel.objects.filter( taker=self.request.user, status__in=(1,2,3), ) context["message"] = self.message return context
你提出的子类化方案的问题
你尝试在子类中直接定义qs类属性,但类属性在类加载阶段就会执行赋值逻辑,此时视图实例还未创建,self.request根本不存在,会直接抛出NameError异常,无法正常运行。
正确的子类化实现方式
应该在基类中定义一个获取查询集的方法,由子类重写该方法来提供不同的查询逻辑,而非直接定义类属性:
基类实现
class MyBaseView(LoginRequiredMixin, TemplateView): template_name = "generic_listings.html" message = "" def get_queryset(self): # 基类强制子类实现该方法,避免遗漏逻辑 raise NotImplementedError("子类必须重写get_queryset方法") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["list_of_stuff"] = self.get_queryset() context["message"] = self.message return context
子类实现
class MyGiverView(MyBaseView): def get_queryset(self): return MyModel.objects.filter( giver=self.request.user, status=1, ) class MyTakerView(MyBaseView): def get_queryset(self): return MyModel.objects.filter( taker=self.request.user, status__in=(1,2,3), )
额外优化建议
- 若多个子类的
message默认值都是空字符串,可直接在基类中定义,子类无需重复声明 - 后续若需扩展通用筛选逻辑,可在基类中添加参数处理逻辑,进一步减少重复代码
内容的提问来源于stack exchange,提问作者ron_g
相关产品推荐
相关产品推荐

