2

前言

在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文档


7 声望2 粉丝