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


    前言

    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 这个插件还有很多其他的功能,不过现阶段已经满足了我的工作需要,所以我也没有再去深入,还有什么功能需要可以直接翻文档吧。

    目前我用到的还是以导出为主,导入的就是更新和新增这一块,没多少花样,如果接下来遇到其他新的需求,我会再更新一篇文章来介绍更新这个插件的功能~

    参考资料

    欢迎交流

    程序设计实验室专注于互联网热门新技术探索与团队敏捷开发实践,在公众号「程序设计实验室」后台回复 linux、flutter、c#、netcore、android、kotlin、java、python 等可获取相关技术文章和资料,同时有任何问题都可以在公众号后台留言~

    It never rains but it pours. 欢迎关注我的公众号:DealiAxy 提供更多技术文章
  • 相关阅读:
    hdu5914 Triangle 【贪心】
    2016中国大学生程序设计竞赛(ccpc 长春) Fraction【模拟】
    hdu 4034 【floyed变形】
    A
    hdu 2553 N皇后问题【dfs】
    【算法入门经典】7.4回溯法【八皇后问题】
    用javascript实现控制一个文本框的输入字数限制,超出字数限制文本框飘红显示-面试题
    Firebug控制台详解
    CSS实现兼容性的渐变背景(gradient)效果
    jQuery学习——入门jQuery选择器之层次选择器
  • 原文地址:https://www.cnblogs.com/deali/p/14329228.html
Copyright © 2020-2023  润新知