# ---------------------------------------
#   程序：admin.py
#   版本：0.3
#   作者：lds
#   日期：2020-08-30
#   语言：Python 3.X
#   说明：django 导入和导出
# ---------------------------------------

import csv

from django.contrib import admin
from django.utils.http import urlquote
from django.http import HttpResponse

from djlds.model import ModelFields


class ExportCsvMixin:
    """
    导出 CSV 格式文件的动作

    支持自定义的内容：
    # 设置导出 Csv 文件的编码
    csv_charset = 'utf-8-sig'  # gb2312 有些字符不支持
    # 自定义导出 ForeignKey 字段内容
    related_fields = {'ForeignKey字段': {'fields': ['字段1', '字段2'], }}
    # 排除导出字段
    csv_export_exclude = []
    # 导出 csv 文件的名字
    export_csv_name = '后台数据'

    # 添加到动作
    actions = ['export_as_csv', 'export_all_as_csv', ]
    """

    def export_as_csv(self, request, queryset, is_all=False):
        if getattr(self, 'using', None):
            queryset = queryset.using(self.using)

        meta = self.model._meta
        related_fields = getattr(self, 'related_fields', {})
        export_exclude = getattr(self, 'csv_export_exclude', [])

        # 获取需要导出的 ForeignKey 字段
        for related_field, data in related_fields.items():
            if getattr(meta.concrete_model, related_field, None):
                cg_model = getattr(meta.concrete_model, related_field).field.related_model
                # 另外一种获取模型的方法
                # [field for field in meta.fields if field.name == 'cg_hetong_bianhao'][0].remote_field.model
                m = ModelFields(cg_model)
            else:
                raise ValueError(f'没有找到 {related_field} 模型')
            data['names'] = []
            for field in data['fields']:
                verbose = m.field_to_verbose(field)
                if verbose is None:
                    raise ValueError(f'没有找到 {field} 字段')
                # 写入标题
                data['names'].append(verbose)

        field_names = []
        # 写入标题
        field_verbose_name = []

        for field in meta.fields:
            if field.name in export_exclude or field.verbose_name in export_exclude:
                continue
            field_names.append(field.name)
            if field.name in related_fields:
                field_verbose_name.extend(related_fields[field.name]['names'])
            else:
                field_verbose_name.append(field.verbose_name)

        response = HttpResponse(content_type='text/csv', charset=getattr(self, 'csv_charset', 'utf-8-sig'))
        export_csv_name = getattr(self, 'export_csv_name', meta)
        if is_all:
            export_filename = urlquote(f'导出 {export_csv_name} 全部内容')
        else:
            export_filename = urlquote(f'导出 {export_csv_name} 中选择的内容')
        response['Content-Disposition'] = f"attachment; filename={export_filename}.csv"
        writer = csv.writer(response)

        writer.writerow(field_verbose_name)
        for obj in queryset:
            rows = []
            for field in field_names:
                if field in related_fields:
                    related_obj = getattr(obj, field, None)
                    if related_obj:
                        for related_field in related_fields[field]['fields']:
                            val = getattr(related_obj, related_field)
                            rows.append(val)
                    else:
                        rows.extend(['' for _ in related_fields[field]['fields']])
                else:
                    val = getattr(obj, field)
                    rows.append(val)
            writer.writerow(rows)

        return response

    def export_all_as_csv(self, request, queryset):
        return self.export_as_csv(request, self.model.objects.all(), is_all=True)

    # Export Selected
    export_as_csv.short_description = "导出已选中（csv）"
    export_all_as_csv.short_description = "导出全部（csv）"


class MultiDBModelAdmin(admin.ModelAdmin):
    """
    在 Django 管理界面中使用多数据库
    https://docs.djangoproject.com/zh-hans/3.0/topics/db/multi-db/#exposing-multiple-databases-in-django-s-admin-interface
    """
    # 要使用的数据库
    using = None

    def save_model(self, request, obj, form, change):
        """
        告诉 Django 将对象保存到“指定”数据库
        """
        obj.save(using=self.using)

    def delete_model(self, request, obj):
        """
        告诉 Django 从“指定”数据库中删除对象
        """
        obj.delete(using=self.using)

    def get_queryset(self, request):
        """
        告诉 Django 在“指定”数据库中查找对象
        """
        return super(MultiDBModelAdmin, self).get_queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        """
        告诉 Django 使用“指定”数据库上的查询填充 ForeignKey 小部件
        """
        return super(MultiDBModelAdmin, self).formfield_for_foreignkey(db_field, request, using=self.using, **kwargs)

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        """
        告诉 Django 使用“指定”数据库上的查询填充 ManyToMany 小部件
        """
        return super(MultiDBModelAdmin, self).formfield_for_manytomany(db_field, request, using=self.using, **kwargs)
