商务合作加Q:411239339

Django数据导入导出神器django-import-export使用

浏览:508次阅读
没有评论

共计 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

正文完
扫码赞助
post-qrcode
 0
果子
版权声明:本站原创文章,由 果子 于2022-08-13发表,共计4246字。
转载说明:除特殊说明外本站文章皆由果较瘦原创发布,转载请注明出处。