• Django-Import-Export插件控制数据导入流程


    前言#

    之前写过两篇跟这个插件有关的文章,可以回顾一下:

    最近有个朋友留言问我一个关于django-import-export插件的问题

    为了形象表达这个问题,我举个书籍管理的例子来描述一下

    数据库表

    id name price
    1 book1 10
    2 book2 20
    3 book3 30

    要导入的Excel表

    id name price tax
    4 book4 40 5
    5 book5 50 6
    6 book6 60 7

    可以看到,Excel里每本书都有价格和税两个属性,但数据库只有价格一个属性

    导入的时候,需要把每本书的价格+税,才是要存入数据的最终价格

    在以前,这种问题场景我会建议直接用pandas来处理数据然后导入,django-import-export插件只用来做数据导出,因为它的文档很简陋,给的例子很难解决实际问题,往往某个需求用pandas手动处理只需要很少时间,用这个插件还得去啃源码和简陋的文档,效率太低了。

    不过本着折腾的精神,还是来研究一下这个用django-import-export到底能不能实现这个功能。(结果当然是可以的,不然也没有这篇文章了)

    分析#

    首先是看官网文档,有一个节点叫import data workflow

    地址:https://django-import-export.readthedocs.io/en/latest/import_workflow.html

    import_data(dataset, dry_run=False, raise_errors=False)

    The import_data() method of Resource is responsible for importing data from a given dataset.

    dataset is required and expected to be a tablib.Dataset with a header row.

    dry_run is a Boolean which determines if changes to the database are made or if the import is only simulated. It defaults to False.

    raise_errors is a Boolean. If True, import should raise errors. The default is False, which means that eventual errors and traceback will be saved in Result instance.

    根据文档,在导入数据的时候,我们可以通过import_data这个hook来对要导入的数据进行处理

    然后这个hook有个参数,dataset,这个是tablib的东西

    关于这个tablib,我之前没用过,查了一下,是requests作者做的库,那想来应该不会差

    官网文档是:https://tablib.readthedocs.io/en/stable/tutorial.html

    写代码#

    直接把官方的代码例子拿来用

    代码仓库:https://github.com/django-import-export/django-import-export

    同样是这个书籍管理的

    Models代码#

    来看看它的model设计

    class Book(models.Model):
        name = models.CharField('Book name', max_length=100)
        author = models.ForeignKey(Author, blank=True, null=True, on_delete=models.CASCADE)
        author_email = models.EmailField('Author email', max_length=75, blank=True)
        imported = models.BooleanField(default=False)
        published = models.DateField('Published', blank=True, null=True)
        published_time = models.TimeField('Time published', blank=True, null=True)
        price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
        added = models.DateTimeField(blank=True, null=True)
    
        categories = models.ManyToManyField(Category, blank=True)
    
        def __str__(self):
            return self.name
    

    很多字段

    要导入的数据#

    依然是官方提供的,各种格式都有,我选csv的,比较方便

    id,name,author_email
    1,Some book,test@example.com
    

    转换成表格长这样

    id name author_email
    1 Some book test@example.com

    可以看到字段比model定义的少很多

    我们要在导入的时候,给dataset加上价格(price)属性

    Resources代码#

    这是原本的代码

    class BookResource(ModelResource):
        class Meta:
            model = Book
    
        def for_delete(self, row, instance):
            return self.fields['name'].clean(row) == ''
    
            return super(BookResource, self).import_data(
                dataset, dry_run, raise_errors, use_transactions,
                collect_failed_rows, rollback_on_validation_errors, **kwargs
    

    现在我们要加一个hook来处理导入的数据

    代码如下

    def import_data(self, dataset: tablib.Dataset, dry_run=False, raise_errors=False,
                    use_transactions=None, collect_failed_rows=False,
                    rollback_on_validation_errors=False, **kwargs):
        cols = []
        for item in dataset['id']:
            cols.append(int(item) * 99)
    
            dataset.append_col(cols, header='price')
            print(dataset)
    		
            return super(BookResource, self).import_data(
                dataset, dry_run, raise_errors, use_transactions,
                collect_failed_rows, rollback_on_validation_errors, **kwargs
            )
    

    使用DataSetappend_col方法来添加一个新的列

    关于这个DataSet的更多操作请参考Tablib的文档

    这部分的具体操作可以根据实际需求来做修改,这里我直接简单粗暴的把ID乘以99

    处理完DataSet之后记得要执行父类的import_data,完成数据导入的操作。

    效果#

    在admin后台执行导入,可以得到以下的结果

    可以看到price属性变成99

    ID NAME AUTHOR AUTHOR_EMAIL IMPORTED PUBLISHED PUBLISHED_TIME PRICE ADDED CATEGORIES
    New 1 Some book test@example.com 0 99

    就OK了,搞定~

    其实还挺简单的,只是官方文档太简陋了,连个例子的没有,只能自己摸索一下

    参考资料#

    虽然前面都有链接,这里再总结一下吧

  • 相关阅读:
    Unity当中的灯光类型
    js:对dom元素class属性进行读取、更新、移除操作
    网络复习题带答案
    Java多线程之线程池
    ZStack出品|制造业专属的VMware迁移方案长啥样?
    AlphaControls控件TsRadioGroup的使用
    git master回退到某个版本
    禁用adb install 安装app功能
    基于SpringBoot的在线题库管理系统的设计与实现(源码+lw+部署文档+讲解等)
    Word控件Spire.Doc 【加密解密】教程(三):用密码加密 PDF 从 word 到 PDF 转换
  • 原文地址:https://www.cnblogs.com/deali/p/16636562.html