常用 Django 的同学看过来, 个人开源的小工具更新啦

2017-05-23 13:33:30 +08:00
 oddcc

书接上文个人第一个开源小项目, 希望能给大家带来方便

可用性比之前上了一个台阶, 欢迎大家使用, 也欢迎提意见和建议, 谢谢!

项目地址: https://github.com/oddcc/django-export-csv

=======================================================

django-export-csv

Introduction

Django 的一个 CSV 导出工具 可以很方便的把 queryset 导出为 CSV 文件, 为了避免导出文件过大, 占用服务器内存, 生成的是 StreamingHttpResponset.

支持通过下面几种方式对导出的 CSV 文件进行定制

  1. 文件名
  2. 导出的时候文件名加 /不加时间戳
  3. 表头是不是使用 verbose_name
  4. 可以排除不想导出的字段
  5. 自定义导出字段的顺序
  6. 自定义表头
  7. 自定义字段的表现形式(serializer)
  8. 支持导出外键, 多对多, 外键反向查询这些关系, 需要自定义

install

Run:

pip install django-export-csv

Support Python 2.7 and 3.5, Django >= 1.8.

usage

使用 CBV 的话, 视图类需要继承ListView(或MultipleObjectMixin的子类)和QueryCsvMixin, 继承之后就可以调用render_csv_response方法把 queryset 导出为 CSV 文件, render_csv_response方法需要一个QuerySetValuesQuerySet的实例作为参数:

使用 CBV

from django_export_csv import QueryCsvMixin
from django.views.generic.list import ListView

from .models import Student


class StudentListView(QueryCsvMixin, ListView):
    queryset = Student.objects.all()

    def get(self, *args, **kwargs):
        return self.render_csv_response(queryset)

使用 FBV

from django_export_csv import render_csv_response


def student_list_view(request):
    if request.method == 'GET':
        queryset = Student.objects.all()
        return render_csv_response(queryset)

定制 CSV

视图类继承了 QueryCsvMixin之后, 就可以使用以下参数自定义 CSV 文件:

  1. filename - (default: None), 是个字符串, 如果不定义, CSV 会根据 model 来生成文件名.
  2. add_datestamp - (default: False), 是个布尔值, 如果为 True 的话, 导出的文件名末尾会添加当前时间的时间戳.
  3. use_verbose_names - (default: True), 是个布尔值, 如果设为 True, CSV 表头的名称会使用 model 中定义的 verbose_name.
  4. exclude_field - (default: []), 是个包含了不想导出的字段名的列表, 不设的话, 默认导出所有字段.
  5. field_order - (default: []), 是个列表, 可以把想定义排序的字段名写在里面, 导出的 CSV 会优先按顺序排列这个参数指定的字段, 再排剩下的字段.
  6. field_header_map - (default: {}), 是个字典, 用于自定义表头, key 应该是字段名, value 是表头中显示的内容, 这个参数的优先级比 verbose_name 高.
  7. field_serializer_map - (default: {}), 是个字典, 用于自定义 serializer, key 是字段名, value 是对应的函数名, 这个函数应该接收一个值并返回相应的内容.
  8. extra_field - (default: []), 是个列表, 用于定义不在数据库表中但又与 model 相关的字段, 比如外键的反向查询, 多对多关系等等, 也可以用于定义任意其他跟 model 相关的字段. 注意如果指定了extra_field参数, field_serializer_map中必须有相应的 serializer 配合才能工作.

e.g:

# data_init.py

import datetime
from .models import Student, College


def create_student_and_get_queryset():
    college1, _ = College.objects.get_or_create(name="College 1st")
    college2, _ = College.objects.get_or_create(name="College 2nd")

    Student.objects.get_or_create(
        name='Jim', age=18, is_graduated=False, birthday=datetime.date(1998,6,6), college=college1
    )
    Student.objects.get_or_create(
        name='Bing', age=22, is_graduated=True, birthday=datetime.date(1994, 2, 6), college=college1
    )
    Student.objects.get_or_create(
        name='Monica', age=25, is_graduated=True, birthday=datetime.date(1991, 2, 6), college=college2
    )

    return Student.objects.all()

# views.py

from django_export_csv import QueryCsvMixin
from django_export_csv import render_csv_response
from django.views.generic.list import ListView

from .models import Student
from .data_init import create_student_and_get_queryset


def boolean_serializer(value):
    if value == True:
        return 'Y'
    else:
        return 'N'
        
        
def college_serializer(obj):
    return obj.college.name


# CBV

class StudentListView(QueryCsvMixin, ListView):
    filename = 'export_student_list'
    add_datestamp = True
    use_verbose_names = True
    exclude_field = ['id']
    field_order = ['name', 'is_graduated']
    field_header_map = {'is_graduated': 'Graduated'}
    field_serializer_map = {'is_graduated': boolean_serializer, 'college': college_serializer}
    queryset = Student.objects.all()
    extra_field = ['college']

    def get(self, *args, **kwargs):
        queryset = create_student_and_get_queryset()
        return self.render_csv_response(queryset)
        

# FBV

def student_list_view(request):
    filename = 'export_student_list'
    add_datestamp = True
    use_verbose_names = True
    exclude_field = ['id']
    field_order = ['name', 'is_graduated']
    field_header_map = {'is_graduated': 'Graduated'}
    field_serializer_map = {'is_graduated': boolean_serializer, 'college': college_serializer}
    extra_field = ['college']

    if request.method == 'GET':
        queryset = create_student_and_get_queryset()
        return render_csv_response(
            queryset, filename=filename, add_datestamp=add_datestamp, use_verbose_names=use_verbose_names,
            exclude_field=exclude_field, field_order=field_order, field_header_map=field_header_map,
            field_serializer_map=field_serializer_map, extra_field=extra_field
        )
3547 次点击
所在节点    Python
8 条回复
corningsun
2017-05-23 14:01:15 +08:00
不错不错

最近有个需求,也是需要导出数据。不过不是直接导出固定的表和字段,render_csv_response 方法能不能接收一个非 queryset 对象?
oddcc
2017-05-23 14:12:58 +08:00
@corningsun 目前不能..
prasanta
2017-05-23 14:31:07 +08:00
请问在什么情况下我会使用这个呢
oddcc
2017-05-23 15:34:30 +08:00
@prasanta 各种管理系统中会用的多一点吧, 主要是公司里很多类似的导出需求, 用这个就方便多了
clampist
2017-05-23 19:05:40 +08:00
感谢分享,很实用啊
uhayate
2017-05-24 09:38:23 +08:00
东西不错,不过看到介绍还是有点懵逼。能写一下应用场景这样最好,举几个例子,这样大家可能更了解它。
oddcc
2017-05-24 10:39:58 +08:00
@uhayate 谢谢建议, 确实介绍中应该包括应用场景..楼上的同学也是提到这一点
lovesecho
2017-05-26 11:55:50 +08:00
django-import-export==0.5.1 目前在用这个,数据不大的话貌似也还凑合。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/363182

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX