#关于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实现数据库导入导出方式就是我分享给大家的内容了 有什么问题或者高见欢迎评论