跳转到主要内容

Django REST Framework的Excel电子表格(xlsx)文件渲染器。

项目描述

DRF Excel:Django REST Framework Excel电子表格(xlsx)渲染器

drf-excel为Django REST Framework提供了一个Excel电子表格(xlsx)渲染器。它使用OpenPyXL创建电子表格并向最终用户提供文件。

需求

我们的目标是支持Django的当前支持版本,以及

  • Django REST Framework >= 3.14
  • OpenPyXL >= 2.4

安装

pip install drf-excel

然后在您的REST_FRAMEWORK设置中添加以下内容

REST_FRAMEWORK = {
    ...

    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
        'drf_excel.renderers.XLSXRenderer',
    ),
}

为了避免在没有文件名的情况下进行文件流(浏览器通常会默认使用没有扩展名的“下载”作为文件名),我们需要使用混入来覆盖Content-Disposition头。如果没有提供filename,则默认为export.xlsx。例如

from rest_framework.viewsets import ReadOnlyModelViewSet
from drf_excel.mixins import XLSXFileMixin
from drf_excel.renderers import XLSXRenderer

from .models import MyExampleModel
from .serializers import MyExampleSerializer

class MyExampleViewSet(XLSXFileMixin, ReadOnlyModelViewSet):
    queryset = MyExampleModel.objects.all()
    serializer_class = MyExampleSerializer
    renderer_classes = (XLSXRenderer,)
    filename = 'my_export.xlsx'

XLSXFileMixin还提供了一个可以覆盖的get_filename()方法,如果您更愿意以程序方式提供文件名而不是filename属性。

升级到2.0.0

要从drf_renderer_xlsx升级到drf_excel 2.0.0,请更新您的导入路径

  • from drf_renderer_xlsx.mixins import XLSXFileMixin变为from drf_excel.mixins import XLSXFileMixin
  • drf_renderer_xlsx.renderers.XLSXRenderer变为drf_excel.renderers.XLSXRenderer
  • 已移除xlsx_date_format_mappings,以column_data_styles取而代之,它提供了更多的灵活性

配置样式

可以通过视图的headercolumn_headerbodycolumn_data_styles属性将样式添加到工作表标题、列标题行、主体和列数据中。可以使用来自OpenPyXL包的任何参数用于字体、对齐、填充和border_side(边框将是单元格的四面)。

如果提供了列数据样式,它将覆盖主体样式

请注意,列数据样式可以接受一个额外的'format'参数,该参数遵循openpyxl格式

class MyExampleViewSet(XLSXFileMixin, ReadOnlyModelViewSet):
    queryset = MyExampleModel.objects.all()
    serializer_class = MyExampleSerializer
    renderer_classes = (XLSXRenderer,)

    column_header = {
        'titles': [
            "Column_1_name",
            "Column_2_name",
            "Column_3_name",
        ],
        'column_width': [17, 30, 17],
        'height': 25,
        'style': {
            'fill': {
                'fill_type': 'solid',
                'start_color': 'FFCCFFCC',
            },
            'alignment': {
                'horizontal': 'center',
                'vertical': 'center',
                'wrapText': True,
                'shrink_to_fit': True,
            },
            'border_side': {
                'border_style': 'thin',
                'color': 'FF000000',
            },
            'font': {
                'name': 'Arial',
                'size': 14,
                'bold': True,
                'color': 'FF000000',
            },
        },
    }
    body = {
        'style': {
            'fill': {
                'fill_type': 'solid',
                'start_color': 'FFCCFFCC',
            },
            'alignment': {
                'horizontal': 'center',
                'vertical': 'center',
                'wrapText': True,
                'shrink_to_fit': True,
            },
            'border_side': {
                'border_style': 'thin',
                'color': 'FF000000',
            },
            'font': {
                'name': 'Arial',
                'size': 14,
                'bold': False,
                'color': 'FF000000',
            }
        },
        'height': 40,
    }
    column_data_styles = {
        'distance': {
            'alignment': {
                'horizontal': 'right',
                'vertical': 'top',
            },
            'format': '0.00E+00'
        },
        'created_at': {
            'format': 'd.m.y h:mm',
        }
    }

您可以在get_bodyget_headerget_column_headerget_column_data_styles方法中动态生成样式属性。

def get_header(self):
    start_time, end_time = parse_times(request=self.request)
    datetime_format = "%H:%M:%S %d.%m.%Y"
    return {
        'tab_title': 'MyReport', # title of tab/workbook
        'use_header': True,  # show the header_title 
        'header_title': 'Report from {} to {}'.format(
            start_time.strftime(datetime_format),
            end_time.strftime(datetime_format),
        ),
        'height': 45,
        'img': 'app/images/MyLogo.png',
        'style': {
            'fill': {
                'fill_type': 'solid',
                'start_color': 'FFFFFFFF',
            },
            'alignment': {
                'horizontal': 'center',
                'vertical': 'center',
                'wrapText': True,
                'shrink_to_fit': True,
            },
            'border_side': {
                'border_style': 'thin',
                'color': 'FF000000',
            },
            'font': {
                'name': 'Arial',
                'size': 16,
                'bold': True,
                'color': 'FF000000',
            }
        }
    }

此外,您还可以将row_color字段添加到您的序列化器中,并填充主体行。

class ExampleSerializer(serializers.Serializer):
    row_color = serializers.SerializerMethodField()

    def get_row_color(self, instance):
        color_map = {'w': 'FFFFFFCC', 'a': 'FFFFCCCC'}
        return color_map.get(instance.alarm_level, 'FFFFFFFF')

配置工作视图选项

视图选项遵循openpyxl工作表视图选项

它们可以在视图中作为属性sheet_view_options设置

class MyExampleViewSet(serializers.Serializer):
    sheet_view_options = {
        'rightToLeft': True, 
        'showGridLines': False
    }

或使用方法get_sheet_view_options

class MyExampleViewSet(serializers.Serializer):
    
    def get_sheet_view_options(self):
        return {
            'rightToLeft': True, 
            'showGridLines': False
        }

控制XLSX标题和值

使用序列化器字段标签作为标题名

默认情况下,标题将使用与API返回相同的'names'。这可以通过在API视图中设置xlsx_use_labels = True来更改。

而不是使用字段名,导出将使用序列化器内部定义的标签。将序列化器字段定义为title = serializers.CharField(label=_("Some title"))将返回Some title而不是title,也支持翻译。如果没有设置标签,它将回退到使用title

忽略字段

默认情况下,所有字段都会导出,但您可能希望从导出中排除一些字段。为此,您可以设置一个数组,其中包含您要排除的字段:xlsx_ignore_headers = [<excluded fields>]

这也适用于嵌套字段,字段之间用点分隔(例如icon.url)。

日期/时间和数字格式

单元格格式遵循openpyxl格式

要设置全局格式,请在settings.py中设置以下变量

# Date formats
DRF_EXCEL_DATETIME_FORMAT = 'mm-dd-yy h:mm AM/PM'
DRF_EXCEL_DATE_FORMAT = 'mm-dd-yy'
DRF_EXCEL_TIME_FORMAT = 'h:mm AM/PM'

# Number formats
DRF_EXCEL_INTEGER_FORMAT = '0%'
DRF_EXCEL_DECIMAL_FORMAT = '0.00E+00'

布尔值名称

TrueFalse作为布尔字段的值并不总是最好的表示,也不支持翻译。

这可以通过在API视图中使用xlsx_boolean_labels来控制。

xlsx_boolean_labels = {True: _('Yes'), False: _('No')}

True替换为Yes,将False替换为No

这也可以在settings.py中全局设置

DRF_EXCEL_BOOLEAN_DISPLAY = {True: _('Yes'), False: _('No')}

自定义列

在API响应中,您可能需要显式返回一个字典,并希望使用其数据显示额外的列。这可以通过传递 xlsx_custom_cols 来完成。

xlsx_custom_cols = {
    'my_custom_col.val1.title': {
        'label': 'Custom column!',
        'formatter': custom_value_formatter
    }
}

### Example function:
def custom_value_formatter(val):
    return val + '!!!'

### Example response:
{ 
    results: [
        {
            title: 'XLSX renderer',
            url: 'https://github.com/wharton/drf-excel'
            returned_dict: {
                val1: {
                    title: 'Sometimes'
                },
                val2: {
                    title: 'There is no way around'
                }
            }
        }
    ]
}

如果没有传递 labeldrf-excel 将在表头显示键名。

formatter 也是可选的,并接受一个函数,该函数将接收到映射到的值(在我们的例子中,它会接收 "Sometimes" 并返回 "Sometimes!!!")。

自定义映射

假设您有一个字段返回一个 dict 而不是简单的 str,您可能不希望返回整个对象,而只返回它的一个值。比如说,status 返回 { value: 1, display: 'Active' }。为了在 status 列中返回 display 值,我们可以这样做

xlsx_custom_mappings = {
    'status': 'display'
}

更常见的情况是,您希望更改值的格式。 xlsx_custom_mappings 也接受函数作为值。假设我们有一个 description 字段,并且出于某种奇怪的原因,我们想要反转文本,我们可以这样做

def reverse_text(val):
    return val[::-1]

xlsx_custom_mappings = {
    'description': reverse_text
}

发行说明和贡献者

维护者

本包由 Wharton Research Data Services 的工作人员创建。我们很高兴 Wharton School 允许我们一定时间向开源项目做出贡献。我们根据项目需求添加功能,并尽可能跟上问题和拉取请求。由于时间限制(我们的全职工作!),没有拉取请求的功能请求可能无法实现,但我们始终欢迎新的想法,并对贡献和用户表示感谢。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源分布

drf_excel-2.4.1.tar.gz (17.4 kB 查看哈希)

上传时间

构建分布

drf_excel-2.4.1-py3-none-any.whl (14.6 kB 查看哈希)

上传时间 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面