如何在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
相关产品推荐
相关产品推荐

