import csv import json import datetime from django.http import HttpResponse from django.utils.encoding import escape_uri_path def flatten_json(y): """ Flatten a nested json object """ out = {} def flatten(x, name=''): if type(x) is dict: for a in x: flatten(x[a], name + a + '_') elif type(x) is list: i = 0 for a in x: flatten(a, name + str(i) + '_') i += 1 else: out[name[:-1]] = x flatten(y) return out def get_signup_info_keys(queryset): """ Collect all unique keys from the signup_info JSON across the queryset """ keys = set() for obj in queryset: if obj.signup_info and isinstance(obj.signup_info, dict): # Flatten the dictionary first to get all nested keys flat_info = flatten_json(obj.signup_info) keys.update(flat_info.keys()) return sorted(list(keys)) def export_signups_csv(modeladmin, request, queryset): """ Export selected signups to CSV, including flattened JSON fields """ opts = modeladmin.model._meta 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) # Base fields to export base_headers = ['ID', '活动标题', '用户昵称', '用户ID', '报名时间', '状态', '关联订单ID'] # Get dynamic JSON keys json_keys = get_signup_info_keys(queryset) # Write header writer.writerow(base_headers + json_keys) # Write data for obj in queryset: row = [ str(obj.id), obj.activity.title, obj.user.nickname if obj.user else 'Unknown', str(obj.user.id) if obj.user else '', obj.signup_time.strftime('%Y-%m-%d %H:%M:%S'), obj.get_status_display(), str(obj.order.id) if obj.order else '' ] # Add JSON data flat_info = {} if obj.signup_info and isinstance(obj.signup_info, dict): flat_info = flatten_json(obj.signup_info) for key in json_keys: val = flat_info.get(key, '') if val is None: val = '' row.append(str(val)) writer.writerow(row) return response export_signups_csv.short_description = "导出选中报名记录为 CSV (含详细信息)" def export_signups_excel(modeladmin, request, queryset): """ Export selected signups to Excel, including flattened JSON fields """ try: from openpyxl import Workbook except ImportError: modeladmin.message_user(request, "请先安装 openpyxl 库以使用 Excel 导出功能", 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 ws.title = str(opts.verbose_name)[:31] # Sheet name limit is 31 chars # Base fields to export base_headers = ['ID', '活动标题', '用户昵称', '用户ID', '报名时间', '状态', '关联订单ID'] # Get dynamic JSON keys json_keys = get_signup_info_keys(queryset) # Write header ws.append(base_headers + json_keys) # Write data for obj in queryset: row = [ obj.id, obj.activity.title, obj.user.nickname if obj.user else 'Unknown', obj.user.id if obj.user else '', obj.signup_time.replace(tzinfo=None) if obj.signup_time else '', # Remove tz for Excel obj.get_status_display(), obj.order.id if obj.order else '' ] # Add JSON data flat_info = {} if obj.signup_info and isinstance(obj.signup_info, dict): flat_info = flatten_json(obj.signup_info) for key in json_keys: val = flat_info.get(key, '') if val is None: val = '' row.append(str(val)) # Ensure string for simplicity, or handle types ws.append(row) wb.save(response) return response export_signups_excel.short_description = "导出选中报名记录为 Excel (含详细信息)"