django-import-export使用 2021-08-04

#关于django-import-export使用

  • django-import-export库支持多种格式,包括xls、csv、json、yaml以及tablib支持的所有其他格式
  • 重点关注一下导入 因为导出的相对于比较容易

1.插件安装

pip install django-import-export

2.settings配置

INSTALLED_APPS = (
    ...
    'import_export',
)

3.model.py

from django.db import models
class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField(default=1)
    gender = models.CharField(default='男')
    created_time = models.DateTimeField(auto_now_add=True)

4.resources.py

from import_export import resources
from .models import Person
class PersonResource(resources.ModelResource):
    class Meta:
        model = Person
       	fields = ('id', 'name', 'age', 'gender', 'created_time')

resources中常用到的Meta字段

  • fields: 导入导出都使用到这里面的字段
  • import_id_fields: 主键字段 通常使用此字段判断是更新还是新增
  • exclude: 剔除的字段
  • export_order: 导出的字段顺序

自定义列名

from import_export.fields import Field

from import_export import resources
from .models import Person
class PersonResource(resources.ModelResource):
	id = Field(attribute='id', column_name='编号')
	name = Field(attribute='name', column_name='姓名')
	# name = Field(attribute='name', column_name=Book.name.field.verbose_name) # 直接拿verbose_name
    class Meta:
        model = Person
       	fields = ('id', 'name', 'age', 'gender', 'created_time')

说明:

  • 如果没有定义column_name导出的时候就会是字段名

  • 如果想定义model里面没有的字段可以自定义添加Field 接上面resource代码

    job = Field(column_name='职业')
    class Meta:
        model = Person
       	fields = ('id', 'name', 'age', 'gender', 'created_time', 'job')
       	
    # 这里自定义了job字段model没有所有得去指定返回内容 使用钩子函数dehydrate_字段名
    # (至于为什么是这样可以查看一下 export_field 这个方法的源码)
    
    def dehydrate_job(self, instance):
    	# 这里instance是Person实例 
    	# 所以一些含有choice字段的可以直接调用 instance.get_xxx_display()用于显示
    	
    	return 'Python工程师'
    
    

5.配置Admin

from .models import Person
from import_export.admin import ImportExportModelAdmin
from import_export.formats import base_formats

@admin.register(Person)
class PersonAdmin(ImportExportModelAdmin):
	formats = (base_formats.XLS, ) # 这里可以指定导入导出格式 默认所有
    resource_class = PersonResource
	
	def get_export_resource_class(self):
		"""
			当导入导出存在字段差异时可重写此方法自定义返回resource_class 
		"""
		return resource_class

6.关于django-import-export导出

  • 推荐使用导入使用Widget做导入(下面是django-import-export提供的Wiget源码)

    class Widget(object):
    """
    A Widget takes care of converting between import and export representations.
    
    This is achieved by the two methods,
    :meth:`~import_export.widgets.Widget.clean` and
    :meth:`~import_export.widgets.Widget.render`.
    """
    def clean(self, value, row=None, *args, **kwargs):
        """
        Returns an appropriate Python object for an imported value.
    
        For example, if you import a value from a spreadsheet,
        :meth:`~import_export.widgets.Widget.clean` handles conversion
        of this value into the corresponding Python object.
    
        Numbers or dates can be *cleaned* to their respective data types and
        don't have to be imported as Strings.
        """
        return value
    
    def render(self, value, obj=None):
        """
        Returns an export representation of a Python value.
    
        For example, if you have an object you want to export,
        :meth:`~import_export.widgets.Widget.render` takes care of converting
        the object's field to a value that can be written to a spreadsheet.
        """
        return force_text(value)
    

    Widget中主要有clean 和 render两个方法

    • 方法介绍
      • clean可以实现对转入进来值转换为你model需要的类型 例如传入进来的手机号是float(15233334444.0)类型 而model是CharField(15233334444)类型 需要做一个类型转换 render 则是在页面显示的结果
    	class HandleMobile(Widget):
    	    def clean(self, value, row=None, *args, **kwargs):
    	    	if isinstance(value, float):
    	    		value = str(value)
    	    	return value.split('.')[0]
    		
    		def render(self, value, obj=None):
    			"""
    				这个方法主要是在导入页面显示出来的值
    			"""
    			return value
    	# 使用方法
    	mobile = fields.Field(attribute='mobile', column_name='手机号', widget=HandleMobile())
    	
    	class CustomForeignKeyWidget(ForeignKeyWidget):
    		"""
    		自定义外键小部件 (由于__init__需要传入一个field 默认是pk)
    		"""
    		def get_queryset(self, value, row, *args, **kwargs):
    			# 此方法默认返回 all() 
    			return self.model.objects.all()
    		
    		def clean(self, value, row=None, *args, **kwargs):
    			# 根据传入的field 以及value 找到具体的实例
    	        val = super(ForeignKeyWidget, self).clean(value)
    	        if val:
    	            return self.get_queryset(value, row, *args, **kwargs).get(**{self.field: val})
    	        else:
    	            return None
    	
    	# 使用方法
    	account = fields.Field(attribute='account',
                  column_name='账号',
                  widget=DepartmentForeignKeyWidget(Account, 'name')) # Account model名 name 是查询的字段
    
    • 如果提供的默认widget不满足自己要求 看看源码重写

7.import_obj

  • 其实实现这个方法也能做到处理数据存储(在没用小部件之前 我也使用此方法达到了效果) 能用小部件实现的就尽量用小部件实现

        def import_obj(self, obj, data, dry_run):
        	"""
            	obj: model实例 
            	data: 数据(dict) 
            	dry_run: If ``dry_run`` is set, or error occurs, transaction
            	will be rolled back(回滚)
            """
            errors = {}
            for field in self.get_import_fields():
                if isinstance(field.widget, widgets.ManyToManyWidget):
                    continue
                try:
                    self.import_field(field, obj, data)
                except ValueError as e:
                    errors[field.attribute] = ValidationError(
                        force_text(e), code="invalid")
            if errors:
                raise ValidationError(errors)
            
    

8.总结

  • 如果大家有业务是需要实现图片导入而图片又是下载地址的需要爬下来的时候推荐大家使用 widget 和 import_obj方法结合来实现 如果单纯使用小部件 + django files + BytesIO 来实现这样保存的图片会存在media当前目录下而不会存在upload_to的地址下面(不知道是不是实现问题)

  • 以上这篇django-import-export实现数据库导入导出方式就是我分享给大家的内容了 有什么问题或者高见欢迎评论

  • django-import-export git 地址

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tuple-Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值