前言
在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
- 导出视图就和普通的list视图类似,同时继承ListModelMixin,GenericViewSet,以及我们的主角XLSXFileMixin
- renderer_classes 指定渲染器,必须要
- queryset 集合
- serializer_class 序列化器
- xlsx_use_labels 默认为False,可要可不要,此属性的作用是设置表头的名称。默认是字段名,为True时,在serializer中结合属性label可以指定表头名称为label值,例如
class ExportSerializer(serializers.Serializer):
name = serializers.SerializerMethodField(label="姓名")
默认表头名称为“name”,为True时,名称为"姓名"
再配置url,向url请求就可以获得一个excel表格。简单的配置就到这里。
小结
要实现导出表格功能,需要:
- 写入配置项
- 在list视图的基础上,继承XLSXFileMixin,设置渲染器renderer、集合queryset、序列化器
- 要想指定表头的名称,添加xlsx_use_labels=True,同时在序列化器中声明字段的label值。默认为模型的字段名。
一些其他属性及功能
在开发导出功能的时候,我们经常会遇到一些其他的功能需求,以下都是在视图类中的设置。
设置导出的文件名称
filename = "my_export.xlsx" # 设置属性 filename
默认为 export.xlsx
还可以通过编写方法去覆盖来设置文件名,方法名:get_filename()忽略字段
xlsx_ignore_headers = [
] # 忽略的字段 此属性是设置在视图类下的,忽略字段也可以在序列化器中实现。(序列化器如果继承的是Serializer不声明就可以,如果是ModelSerializer可以使用,也可以通过重写序列化器中的to_representation()方法。)
命名布尔值
xlsx_boolean_labels = {True: _('Yes'), False: _('No')}
将布尔值中的True替换为Yes,False替换为No,也可在serilaizer中处理。
- 自定义映射——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就是表格对象。遍历,映射,更新字段值
- 与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的熟练结合,可以使得需求实现变得多方案、更简便。开发学习中,了解源码还是比较重要的。