共计 4246 个字符,预计需要花费 11 分钟才能阅读完成。
前言
Django 以快速开发闻名,但是如果处理数据的导出导入还需要自己写脚本,那就有违“Python 之禅”了……
而且导数据通常需要不同的格式,Excel、csv、json 等,每种格式的数据就要写一个脚本太麻烦了,这时直接祭出 django-import-export 这个神器,官方一句话介绍:django-import-export is a Django application and library for importing and exporting data with included admin integration.
特点
support multiple formats (Excel, CSV, JSON, … and everything else that tablib support)
admin integration for importing
preview import changes
admin integration for exporting
export data respecting admin filters
反正好用就完事了,下面我开始上使用介绍
首先安装
pip install django-import-export
然后得添加到 INSTALLED_APPS 里面
# settings.py
INSTALLED_APPS = (
...
'import_export',
)
编写 Resource
不得不说,这很 Django
Resource 的写法与 Model、Form 类似,就是定义你要导入或者导出的数据格式。
这里借用一下官方的例子,首先上 Model 代码
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
name = models.CharField('Book name', max_length=100)
author = models.ForeignKey(Author, blank=True, null=True)
author_email = models.EmailField('Author email', max_length=75, blank=True)
imported = models.BooleanField(default=False)
published = models.DateField('Published', blank=True, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
categories = models.ManyToManyField(Category, blank=True)
def __str__(self):
return self.name
现在要导入数据到 Book 表,开始编写我们的 Resource,我是在 app 所在目录下创建一个 resource.py 来放 Resource 定义代码
from import_export import resources
from core.models import Book
class BookResource(resources.ModelResource):
class Meta:
model = Book
这样一个最简单的 Resource 就定义好了,可以使用代码进行数据导出,但现在我不想用,因为我要把导出功能放在 DjangoAdmin 后台里面
配置 Admin
修改 admin.py,修改的地方就是把我们定义的 Admin 类原本继承的 admin.ModelAdmin 改成 ImportExportModelAdmin,代码如下
from .models import Book
from import_export.admin import ImportExportModelAdmin
class BookAdmin(ImportExportModelAdmin):
resource_class = BookResource
admin.site.register(Book, BookAdmin)
这样就可以在后台看到有导出和导入的按钮了。
只想导出不想有导入功能咋办,改成这样:
from .models import Book
from django.contrib import admin
from import_export.admin import ExportMixin
class BookAdmin(ExportMixin, admin.ModelAdmin):
resource_class = BookResource
admin.site.register(Book, BookAdmin)
只导入不导出也行,把 ExportMixin 换成 ImportMixin 就行。
当然这些只是最简单的用法,实际需求是比较复杂的,接下来我列举几个我用到的。
调整字段顺序
要导入的数据(Excel、csv 这些),可能字段顺序和 Model 定义的字段顺序不一样,这时就得在 Resource 里手动调整一下
由于我自己写的代码涉及到公司业务,所以继续借用官网的代码例子:
class BookResource(resources.ModelResource):
class Meta:
model = Book
fields = ('id', 'name', 'author', 'price',)
export_order = ('id', 'price', 'author', 'name')
其中 export_order 是导出的字段顺序,fields 是指定哪些字段需要导入,导入的时候是根据数据文件的列名来导入的,所以 Excel、csv 或者 json 文件里面字段名就要和 fields 里的或者是 Model 里的字段名一样,才可以进行导入。
排除字段
顾名思义,就拿那个 Book 的模型来说,Model 定义里没有指定主键,那 Django 会安排一个默认的主键字段 id,但是我们导入数据的 Excel 里应该是没有这个 id 的,这样就没法导入,于是我们得把这个 id 字段排除了,很简单,在 Meta 里这行代码
exclude = ['id']
设置主键字段
也是顾名思义,假如我们数据库本来就有很多书了,现在需要通过导入一个 Excel 来更新这批书的数据,那我就得把找一个字段来设置成主键字段,不然导入就变成新增了,跟前面提到的一样,一般 Excel 里不会有数据库主键 id 的,所以这里我选择了书名(假设我们这是一个小书店,书名都不重复的)
代码:
import_id_fields = ['name']
自定义列名
按照前文配置导出来的 Excel,列名全是字段名,也就是英文的,但我想中文列名啊,也可以,就是需要花一点代码(这里就不再借用官网代码了,我自己手打)
from import_export.fields import Field
class BookResource(resources.ModelResource):
id = Field(attribute='id', column_name='编号')
name = Field(attribute='name', column_name='书籍名称')
class Meta:
model = Book
export_order = ('id', 'name', 'author', 'price',)
这样就实现了,so easy。其中 Field 里的 attribute 是指这个字段对应 Model 里的属性也就是字段名,column_name 顾名思义就是列名。
然后可能有同学要问,Model 里已经给每个字段都设置了 verbose_name 了,这里还要在 column_name 里再写一遍是不是重复了?
别急,也很简单,既然有 verbose_name,那直接拿来用就完事啦~
name = Field(attribute='name', column_name=Book.name.field.verbose_name)
这就完事美滋滋啦~
#### 加入自定义的列
最后一个,如果想在导出的数据中加入 Model 里不存在的字段,行不?
那肯定行啊,也很简单,直接代码:
from import_export.fields import Field
class BookResource(resources.ModelResource):
id = Field(attribute='id', column_name='编号')
name = Field(attribute='name', column_name='书籍名称')
new_field = Field(column_name='一个新的字段')
class Meta:
model = Book
export_order = ('id', 'name', 'author', 'price', 'new_field')
@staticmethod
def dehydrate_new_field(instance: Book):
return '新字段内容'
可以看到就是先在 export_order 里添加这个字段,然后再加这行 new_field = Field(column_name=’ 一个新的字段 ’),然后下面加一个类方法来实现生成这个字段的值,这个方法是以 dehydrate_字段名这样的格式来命名的,具体可以根据实际来写。
总结
django-import-export 这个插件还有很多其他的功能,不过现阶段已经满足了我的工作需要,所以我也没有再去深入,还有什么功能需要可以直接翻文档吧。
目前我用到的还是以导出为主,导入的就是更新和新增这一块,没多少花样,如果接下来遇到其他新的需求,我会再更新一篇文章来介绍更新这个插件的功能~
参考资料
项目主页:https://github.com/django-import-export/django-import-export
官方文档:https://django-import-export.readthedocs.io/en/latest/installation.html
转载自:https://zhuanlan.zhihu.com/p/346597035
