Files
Scoring-System/backend/shop/admin_actions.py

111 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import csv
import datetime
from django.http import HttpResponse
from django.utils.encoding import escape_uri_path
def export_to_csv(modeladmin, request, queryset):
"""
通用导出 CSV 的 Admin Action
支持中文编码UTF-8 BOM可直接用 Excel 打开
"""
opts = modeladmin.model._meta
# 设置文件名,使用模型的 verbose_name
filename = f"{opts.verbose_name}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
response = HttpResponse(content_type='text/csv; charset=utf-8-sig')
response['Content-Disposition'] = f'attachment; filename={escape_uri_path(filename)}'
writer = csv.writer(response)
# 获取所有非多对多字段和非反向关联字段
fields = [field for field in opts.get_fields() if not field.many_to_many and not field.one_to_many]
# 写入表头 (使用字段的 verbose_name)
writer.writerow([field.verbose_name for field in fields])
# 写入数据
for obj in queryset:
data_row = []
for field in fields:
value = getattr(obj, field.name)
# 处理 Choice 字段,显示可读的标签
if hasattr(obj, f'get_{field.name}_display'):
value = getattr(obj, f'get_{field.name}_display')()
# 处理关联对象ForeignKey
if field.is_relation and value:
value = str(value)
# 处理日期时间
if isinstance(value, datetime.datetime):
value = value.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(value, datetime.date):
value = value.strftime('%Y-%m-%d')
# 处理 None
if value is None:
value = ""
data_row.append(str(value))
writer.writerow(data_row)
return response
export_to_csv.short_description = "导出选中项为 CSV"
def export_to_excel(modeladmin, request, queryset):
"""
导出为 Excel (需要安装 openpyxl)
"""
try:
from openpyxl import Workbook
except ImportError:
modeladmin.message_user(request, "请先安装 openpyxl 库以使用 Excel 导出功能: pip install openpyxl", level='error')
return
opts = modeladmin.model._meta
filename = f"{opts.verbose_name}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
response = HttpResponse(
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
)
response['Content-Disposition'] = f'attachment; filename={escape_uri_path(filename)}'
wb = Workbook()
ws = wb.active
# Sheet name limit is 31 chars
ws.title = str(opts.verbose_name)[:31]
fields = [field for field in opts.get_fields() if not field.many_to_many and not field.one_to_many]
# 写入表头
ws.append([str(field.verbose_name) for field in fields])
# 写入数据
for obj in queryset:
row = []
for field in fields:
value = getattr(obj, field.name)
if hasattr(obj, f'get_{field.name}_display'):
value = getattr(obj, f'get_{field.name}_display')()
# 处理关联对象ForeignKey
if field.is_relation and value:
value = str(value)
if isinstance(value, (datetime.datetime, datetime.date)):
# openpyxl 可以直接处理 datetime 格式Excel 会自动识别
# 但为了避免时区问题,通常转为无时区时间或字符串
if isinstance(value, datetime.datetime):
value = value.replace(tzinfo=None)
row.append(value)
ws.append(row)
wb.save(response)
return response
export_to_excel.short_description = "导出选中项为 Excel"