You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中践行DRY原则:如何重构Views层重复的列表视图代码

Django多相似列表视图的优化实现方案

你当前的装饰器方案将公共逻辑完全封装在装饰器内部,阻断了视图函数的扩展空间,以下提供两种可实现个性化扩展的优化方案:

方案1:基于类视图实现(推荐,符合Django最佳实践)

将公共逻辑抽离到父类视图中,普通视图仅需指定模板路径即可,需要自定义逻辑的视图直接覆写对应方法即可。

基础父类实现

from django.views.generic import View
from django.shortcuts import render
from django.db.models import Avg
from .models import Bacteria
from .filters import BacteriaFilter

class BaseBacteriaListView(View):
    # 子类仅需覆写该属性指定模板路径
    template_name = ""

    def get(self, request, *args, **kwargs):
        # 所有列表视图公共逻辑
        bacteria = Bacteria.objects.all()
        bacteria_count = bacteria.count()
        bacteriaFilter = BacteriaFilter(request.GET, queryset=bacteria)
        bacteria = bacteriaFilter.qs
        remaining = bacteria.count()
        common_tags = Bacteria.tags.most_common()[:8]

        # 上下文单独抽离为方法,方便子类扩展
        context = self.get_extra_context({
            "bacteria": bacteria,
            "common_tags": common_tags,
            "bacteria_count": bacteria_count,
            "bacteriaFilter": bacteriaFilter,
            "remaining": remaining
        }, request, *args, **kwargs)
        return render(request, self.template_name, context)

    def get_extra_context(self, base_context, request, *args, **kwargs):
        # 默认返回基础上下文,子类可重写该方法新增/修改上下文变量
        return base_context

无自定义逻辑的普通视图使用示例

仅需继承父类指定模板路径即可,比原装饰器写法更简洁:

class GeneralPhysiologyView(BaseBacteriaListView):
    template_name = "bacteria/generalPhysiology.html"

class EnzymeActivityTableView(BaseBacteriaListView):
    template_name = "bacteria/enzymeActiveTable.html"

有个性化逻辑的视图使用示例

直接重写对应方法即可,支持扩展查询逻辑、上下文变量等:

class EnzymeActivityTableView(BaseBacteriaListView):
    template_name = "bacteria/enzymeActiveTable.html"

    def get_extra_context(self, base_context, request, *args, **kwargs):
        # 继承原有基础上下文
        context = super().get_extra_context(base_context, request, *args, **kwargs)
        # 新增个性化变量
        context["enzyme_avg_activity"] = Bacteria.objects.aggregate(avg_activity=Avg("activity"))["avg_activity"]
        # 支持修改原有上下文变量
        context["common_tags"] = Bacteria.tags.most_common()[:12]
        return context

URL配置示例

urlpatterns = [
    path('general-physiology/', GeneralPhysiologyView.as_view(), name='general_physiology'),
    path('enzyme-activity/', EnzymeActivityTableView.as_view(), name='enzyme_activity'),
]

方案2:改造现有装饰器(兼容原有代码,无需修改现有URL配置)

如果你不想改动现有代码结构,可以对原装饰器进行改造,增加扩展入口,让被装饰的视图函数返回的字典自动合并到模板上下文中:

改造后的装饰器代码

def my_decorator(html=""):
    def decorator(view_func):
        def wrapper(request, *args, **kwargs):
            # 公共逻辑保持不变
            bacteria = Bacteria.objects.all()
            bacteria_count = bacteria.count()
            bacteriaFilter = BacteriaFilter(request.GET, queryset=bacteria)
            bacteria = bacteriaFilter.qs
            remaining = bacteria.count()
            common_tags = Bacteria.tags.most_common()[:8]

            # 显式构造基础上下文,替代原locals()避免引入无关变量
            base_context = {
                "bacteria": bacteria,
                "common_tags": common_tags,
                "bacteria_count": bacteria_count,
                "bacteriaFilter": bacteriaFilter,
                "remaining": remaining
            }
            # 执行原视图函数,若返回字典则合并到上下文中
            extra_context = view_func(request, *args, **kwargs)
            if isinstance(extra_context, dict):
                base_context.update(extra_context)
            return render(request, html, base_context)
        return wrapper
    return decorator

使用示例

原有无自定义逻辑的视图无需任何修改,保持原样即可:

@my_decorator(html="bacteria/generalPhysiology.html")
def general_physiology_view(request):
    pass

需要添加个性化逻辑的视图直接返回字典即可:

@my_decorator(html="bacteria/enzymeActiveTable.html")
def enzyme_activity_table_view(request):
    # 个性化业务逻辑
    avg_activity = Bacteria.objects.aggregate(avg_activity=Avg("activity"))["avg_activity"]
    # 返回的字典会自动合并到模板上下文
    return {
        "enzyme_avg_activity": avg_activity,
        "common_tags": Bacteria.tags.most_common()[:12]
    }

方案对比

  • 类视图方案:扩展性更强,逻辑分层清晰,适合后期有大量自定义需求的场景,是Django官方推荐的实现方式
  • 装饰器改造方案:完全兼容现有代码,无需修改原有URL配置,适合不想大动现有项目结构的场景

内容的提问来源于stack exchange,提问作者Danhr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 23:27:03