Django-DRF导出excel表格,drf-renderer-xlsx的使用

前言

在DRF中,生成excel表格最方便的是借助第三方插件drf-renderer-xlsx,使得“导出”功能变得和写普通视图一样简单、方便、快捷。其思想是基于列表,毕竟list方法生成的queryset已经和所需要的表格结构类似了,只是需要放在表格文件中。

版本

drf-renderer-xlsx==0.4.3
Django==3.1.4
djangorestframework==3.12.4

配置

将以下配置写入 REST_FRAMEWORK

REST_FRAMEWORK = {
    "DEFAULT_RENDERER_CLASSES": [
        "rest_framework.renderers.JSONRenderer",
        "rest_framework.renderers.BrowsableAPIRenderer",
        "drf_renderer_xlsx.renderers.XLSXRenderer",
    ],
}

视图

首先看一个简单的导出视图实现

from drf-renderer-xlsx import XLSXFileMixin
from drf-renderer-xlsx import XLSXRenderer
from rest_framework import viewsets, filters, mixins

class ExportViewSet(mixins.ListModelMixin, GenericViewSet, XLSXFileMixin):
    renderer_classes = (XLSXRenderer,)
    queryset = Model.objects.all()
    serializer_class = ExportSerializer
    xlsx_use_labels = True
  1. 导出视图就和普通的list视图类似,同时继承ListModelMixin,GenericViewSet,以及我们的主角XLSXFileMixin
  2. renderer_classes 指定渲染器,必须要
  3. queryset 集合
  4. serializer_class 序列化器
  5. xlsx_use_labels 默认为False,可要可不要,此属性的作用是设置表头的名称。默认是字段名,为True时,在serializer中结合属性label可以指定表头名称为label值,例如
class ExportSerializer(serializers.Serializer):
    name = serializers.SerializerMethodField(label="姓名")

默认表头名称为“name”,为True时,名称为"姓名"

再配置url,向url请求就可以获得一个excel表格。简单的配置就到这里。

小结

要实现导出表格功能,需要:

  1. 写入配置项
  2. 在list视图的基础上,继承XLSXFileMixin,设置渲染器renderer、集合queryset、序列化器
  3. 要想指定表头的名称,添加xlsx_use_labels=True,同时在序列化器中声明字段的label值。默认为模型的字段名。

一些其他属性及功能

在开发导出功能的时候,我们经常会遇到一些其他的功能需求,以下都是在视图类中的设置

  1. 设置导出的文件名称

     filename = "my_export.xlsx"  # 设置属性 filename

    默认为 export.xlsx
    还可以通过编写方法去覆盖来设置文件名,方法名:get_filename()

  2. 忽略字段

     xlsx_ignore_headers = [<fieldname>] # 忽略的字段

    此属性是设置在视图类下的,忽略字段也可以在序列化器中实现。(序列化器如果继承的是Serializer不声明就可以,如果是ModelSerializer可以使用,也可以通过重写序列化器中的to_representation()方法。)

  3. 命名布尔值

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

    将布尔值中的True替换为Yes,False替换为No,也可在serilaizer中处理。

  4. 自定义映射——xlsx_custom_cols
    使用场景:就我个人来说目前遇到的使用场景是,数据库中的这个字段存储的时候就是以映射存储的,比如问卷调查的结果,每个用户的每道题答案是根据映射存储的,(比如1,2,3)这样,导出的时候需要复原成选项文字。
def list(self, request, *args, **kwargs):
    .......
    for i in results:
        for k,v in i.items():
             self.xlsx_custom_cols.update({k: {"label": k, "formatter": v}})
     return Response(results)

results就是表格对象。遍历,映射,更新字段值

  1. 与DRF的结合:筛选、权限、排序
class ExportViewSet(viewsets.ReadOnlyModelViewSet, XLSXFileMixin):
    authentication_classes = (JWTAuthentication,)                   # 认证
    filter_backends = (BaseFilterBackend, filters.OrderingFilter)  # 筛选
    filter_class = ExportFilter                                   # 筛选字段
    renderer_classes = (XLSXRenderer)                           # 渲染器
    permission_classes = (IsAuthenticated, )                  # 权限
    queryset = Model.objects.all()                            # 集合
    serializer_class = ExportSerializer                          #序列化器
    xlsx_use_labels = True                                   # 表头名称替换

另外:
由于我的Model有很多状态字段需要维护,这些字段都是用带映射的SmallIntegerField字段做的,
在导出的时候,也需要输出映射值
例如:
model:

from django.utils.translation import gettext_lazy as _T

class Model(models.Model):
    class StatusChoices(models.IntegerChoices):
        PAID = 1, _T("已支付")
        REFUND = 2, _T("退款")
        REFUNDING = 3, _T("退款中")
        UNREFUND = 4, _T("未退款")
    
    status = models.SmallIntegerField(
        default=StatusChoices.PAID,
        help_text="订单状态",
        choices=StatusChoices.choices,
)

serializer:

class ExportSerilaizer(serializers.Serializer):
    status = serializers.SerializerMethodField(label="订单状态")

    def get_status(self, instance):
         return instance.get_status_display()

在序列化器中重写方法,后面跟_display(),就可以使得字段输出为映射的中文值 > "已支付"\"退款"

大部分关于字段值的更改,都可以在serializer中实现。

总结

第三方插件的使用,与DRF、Django的熟练结合,可以使得需求实现变得多方案、更简便。开发学习中,了解源码还是比较重要的。

参考

drf-renderer-xlsx文档

6 声望
2 粉丝
0 条评论
推荐阅读
python里打印list的四种方法
原文链接标题:Print lists in Python (4 Different Ways)用for循环来打印 {代码...} 结果1 2 3 4 5用 * 星号来打印 {代码...} 结果 {代码...} 把list转换为str来打印 {代码...} 结果 {代码...} 用map把数组里非...

chiiinnn阅读 10.4k

封面图
Ubuntu20.04 从源代码编译安装 python3.10
Ubuntu 22.04 Release DateUbuntu 22.04 Jammy Jellyfish is scheduled for release on April 21, 2022If you’re ready to use Ubuntu 22.04 Jammy Jellyfish, you can either upgrade your current Ubuntu syste...

ponponon1阅读 4k评论 1

日常Python 代码片段整理
1、简单的 HTTP Web 服务器 {代码...} 2、单行循环List {代码...} 3、更新字典 {代码...} 4、拆分多行字符串 {代码...} 5、跟踪列表中元素的频率 {代码...} 6、不使用 Pandas 读取 CSV 文件 {代码...} 7、将列表...

墨城2阅读 336

Unicode 正则表达式(qbit)
前言本文根据《精通正则表达式》和 Unicode Regular Expressions 整理。本文的示例默认以 Python3 为实现语言,用到 Python3 的 re 模块或 regex 库。基本的 Unicode 属性分类 {代码...} 基本的 Unicode 子属性Le...

qbit阅读 4.4k

Python + Sqlalchemy 对数据库的批量插入或更新(Upsert)
由于不同数据库对这种 upsert 的实现机制不同,Sqlalchemy 也就不再试图做一致性的封装了,而是提供了各自的方言 API,具体到 Mysql,就是给 insert statement ,增加了 on_duplicate_key_update 方法。

songofhawk1阅读 2k评论 4

封面图
打脸了兄弟们,Go1.20 arena 来了!
大家好,我是煎鱼。大概半年前,我写过一篇文章《Go 要违背初心吗?新提案:手动管理内存》。有兴趣了深入解的同学,可以再回顾一下。当时我们还想着 Go 团队应该不会接纳,至少不会那么快:懒得翻也可以看我再次...

煎鱼1阅读 3.3k

uwsgi 注意事项
http 和 http-socket 选项是完全不同的。第一个生成一个额外的进程,转发请求到一系列的worker (将它想象为一种形式的盾牌,与apache或者nginx同级),而第二个设置worker为原生使用http协议。

zed2015阅读 2.2k

6 声望
2 粉丝
宣传栏