4

Django-Import-Export插件控制数据导入流程 - 程序设计实验室

 1 year ago
source link: https://www.cnblogs.com/deali/p/16636562.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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,[email protected]

转换成表格长这样

id name author_email
1 Some book [email protected]

可以看到字段比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 [email protected] 0 99

就OK了,搞定~

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

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

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK