在Django CBV中遵循DRY原则:同模型不同过滤视图如何复用代码
解决方案
你可以通过抽象公共父类的方式消除所有重复代码,把公共逻辑封装到基础视图中,仅将可变参数做成可配置的类属性即可。
方法1:抽象公共基类(扩展性强,推荐)
优化后views.py代码
from django.views.generic import ListView from django.contrib.auth.mixins import LoginRequiredMixin from .models import Block # 封装所有公共逻辑的基础视图 class BaseBlockListView(LoginRequiredMixin, ListView): # 固定公共属性直接写在基类 template_name = 'blocks/blockslist.html' model = Block # 可变配置项,子类仅需要修改这几个参数即可 page = None filter_status = None page_title = None def get_queryset(self): # 直接调用父类查询方法,结合配置的状态过滤 return super().get_queryset().filter( user=self.request.user, status=self.filter_status ) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 动态注入公共上下文变量 context['page'] = self.page context['page_title'] = self.page_title return context # 子类仅需要配置差异化参数,无任何重复逻辑 class AcceptedBlockView(BaseBlockListView): page = 'acceptedblock' filter_status = 'Accepted' page_title = '已接收区块' class CompletedBlockView(BaseBlockListView): page = 'completedblock' filter_status = 'Completed' page_title = '已完成区块'
方法2:直接在URL配置传参(更简洁,适合简单场景)
如果不需要给子类加额外逻辑,甚至可以不用定义多个视图类,直接在urls.py中通过as_view传递配置参数:
from django.urls import path from .views import BaseBlockListView urlpatterns = [ path('accepted/', BaseBlockListView.as_view( page='acceptedblock', filter_status='Accepted', page_title='已接收区块' ), name='acceptedblock'), path('completed/', BaseBlockListView.as_view( page='completedblock', filter_status='Completed', page_title='已完成区块' ), name='completedblock'), # 后续新增其他状态的列表页,只需要加一行URL配置即可,无需修改views代码 ]
可选优化:简化HTML模板
可以把页面标题做成变量传入,去掉模板里的硬编码判断,让模板更通用:
<h2>{{ page_title }}</h2> <table> <thead class="thed-dark"> <tr> <th>#</th> <th>Title</th> <th>Update Block</th> <th>Status</th> <th>User</th> </tr> </thead> <tbody> {% for instance in object_list %} <tr> <td>{{ forloop.counter }}</td> <td>{{ instance.title }}</td> <td><a href="{% url 'updateblock' instance.id %}">Update</a></td> <td>{{ instance.status }}</td> <td>{{ instance.user }}</td> </tr> {% endfor %} </tbody> </table> <p>点击查看 <a href="{% url 'allblocks' %}">所有区块</a></p> <p>点击查看 <a href="{% url 'acceptedblock' %}">已接收区块</a></p> </div>
内容的提问来源于stack exchange,提问作者Visionary
相关产品推荐
相关产品推荐

