forked from quant-speed-AI/Scoring-System
创赢未来评分系统 - 初始化提交(移除大文件)
This commit is contained in:
110
backend/shop/admin_actions.py
Normal file
110
backend/shop/admin_actions.py
Normal file
@@ -0,0 +1,110 @@
|
||||
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"
|
||||
Reference in New Issue
Block a user