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

如何在Django类视图中遵循DRY原则实现不同筛选的Excel下载?

符合DRY原则的Django Excel导出视图优化方案

你之前的子类写法无效,因为在子类get方法里定义的rows是局部变量,父类的get方法根本访问不到它。要实现不同筛选条件的Excel导出且不重复代码,最优方案是把父类里的可变逻辑抽成可重写的独立方法,让子类只需要覆盖这些差异点即可,完全遵循DRY原则。

原视图代码

class ExcelDownloadAllView(TemplateView):
    def get(self, request, *args, **kwargs):
        response = HttpResponse(content_type='application/ms-excel')
        response['Content-Disposition'] = 'attachment; filename="All_of_Projects.xls"'

        wb = xlwt.Workbook(encoding='utf-8')
        ws = wb.add_sheet('All Projects Data') # this will make a sheet named Users Data

        # Sheet header, first row
        row_num = 0

        font_style = xlwt.XFStyle()
        font_style.font.bold = True

        columns = ['Username', 'First Name', 'Last Name', 'Email Address', 'Summary']
        rows = BugTracker.objects.all().values_list('project_number','assignee','priority','status','summary',) 

        for col_num in range(len(columns)):
            ws.write(row_num, col_num, columns[col_num], font_style) # at 0 row 0 column 

        # Sheet body, remaining rows
        font_style = xlwt.XFStyle()
        for row in rows:
            row_num += 1
            for col_num in range(len(row)):
                ws.write(row_num, col_num, row[col_num], font_style)

        wb.save(response)

        return response

尝试的无效子类代码

class ExcelDownloadOpenView(ExcelDownloadAllView):
    
    def get(self, request, *args, **kwargs):
        rows = BugTracker.objects.all().values_list('project_number','assignee', 'priority')
        return super().get(request, *args, **kwargs)

优化后的实现方案

1. 重构父类,抽离可变逻辑

将原父类中文件名、工作表名、表头列、数据行这些可变部分封装成独立的可重写方法,核心导出逻辑保留在get方法中:

from django.views.generic.base import TemplateView
from django.http import HttpResponse
import xlwt
from .models import BugTracker

class ExcelDownloadAllView(TemplateView):
    # 可重写:导出文件名
    def get_filename(self):
        return "All_of_Projects.xls"
    
    # 可重写:工作表名称
    def get_sheet_name(self):
        return "All Projects Data"
    
    # 可重写:表头列
    def get_columns(self):
        return ['Username', 'First Name', 'Last Name', 'Email Address', 'Summary']
    
    # 可重写:数据行(核心筛选逻辑)
    def get_rows(self):
        return BugTracker.objects.all().values_list(
            'project_number','assignee','priority','status','summary'
        )

    def get(self, request, *args, **kwargs):
        response = HttpResponse(content_type='application/ms-excel')
        # 使用get_filename方法获取文件名
        response['Content-Disposition'] = f'attachment; filename="{self.get_filename()}"'

        wb = xlwt.Workbook(encoding='utf-8')
        # 使用get_sheet_name方法获取工作表名
        ws = wb.add_sheet(self.get_sheet_name())

        row_num = 0
        # 表头样式
        font_style = xlwt.XFStyle()
        font_style.font.bold = True

        # 通过方法获取表头和数据
        columns = self.get_columns()
        rows = self.get_rows()

        # 写入表头
        for col_num in range(len(columns)):
            ws.write(row_num, col_num, columns[col_num], font_style)

        # 写入数据行
        font_style = xlwt.XFStyle()
        for row in rows:
            row_num += 1
            for col_num in range(len(row)):
                ws.write(row_num, col_num, row[col_num], font_style)

        wb.save(response)
        return response

2. 子类仅重写差异方法

现在子类只需要覆盖需要修改的方法即可,不用重复整个导出逻辑:

class ExcelDownloadOpenView(ExcelDownloadAllView):
    # 重写导出文件名
    def get_filename(self):
        return "Open_Projects.xls"
    
    # 重写工作表名称
    def get_sheet_name(self):
        return "Open Projects Data"
    
    # 重写表头列(匹配数据字段)
    def get_columns(self):
        return ['Project Number', 'Assignee', 'Priority']
    
    # 重写数据行,添加筛选条件
    def get_rows(self):
        # 示例:仅导出状态为"Open"的bug数据
        return BugTracker.objects.filter(status='Open').values_list(
            'project_number','assignee', 'priority'
        )

为什么这个方案有效?

  • 父类的核心导出逻辑只实现一次,子类仅关注自身的差异点,完全遵循DRY原则
  • 通过类方法传递可变内容,替代之前的局部变量赋值,确保子类的修改能被父类的核心逻辑正确使用
  • 扩展性强:后续新增其他筛选导出视图时,只需要继承父类并重写对应的方法即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 15:41:47