Skip to content

Instantly share code, notes, and snippets.

@daimon99
Last active February 28, 2020 13:44
Show Gist options
  • Save daimon99/91cbb9d2a475c6b61df66cdd106a8e85 to your computer and use it in GitHub Desktop.
Save daimon99/91cbb9d2a475c6b61df66cdd106a8e85 to your computer and use it in GitHub Desktop.
Custom django import export resource class, using verbose_name as export file header, and support clean field in the resource class。自定义的 django import export resource 类,支持用 verbose_name 作为导出/导入文件的列名,并支持在 Resouce 类中直接 clean 字段值
# coding: utf-8
from collections import OrderedDict
from copy import deepcopy
from django.core.exceptions import ValidationError
from django.utils.encoding import force_str
from import_export import resources, widgets
from . import models as m
TIMESTAMP_FIELDS = ['created', 'modified']
class VerboseNameModelResource(resources.ModelResource):
"""
自定义的导入/导出资源基类。特点:
#. 导出/导入 excel header 为 verbose_name
#. 支持在 Resouce 类中定义 clean_<column_name> 方法,来清理导入的数据。可以用来把名称转换为外键的key
"""
class Meta:
import_id_fields = ['ID']
def __init__(self):
super().__init__()
verbose_name_fields = OrderedDict()
for i in self.fields:
verbose_name_fields[self.fields[i].column_name] = self.fields[i]
self.fields = deepcopy(verbose_name_fields)
@classmethod
def field_from_django_field(cls, field_name, django_field, readonly):
FieldWidget = cls.widget_from_django_field(django_field)
widget_kwargs = cls.widget_kwargs_for_field(field_name)
field = cls.DEFAULT_RESOURCE_FIELD(
attribute=field_name,
column_name=django_field.verbose_name,
widget=FieldWidget(**widget_kwargs),
readonly=readonly,
default=django_field.default,
)
return field
def import_obj(self, obj, data, dry_run):
errors = {}
for field in super().get_import_fields():
if isinstance(field.widget, widgets.ManyToManyWidget):
continue
try:
field_clean_method = getattr(self, f'clean_{field.column_name}', None)
if field_clean_method:
field_clean_method(obj, data)
self.import_field(field, obj, data)
except ValueError as e:
errors[field.column_name] = ValidationError(
force_str(e), code="invalid")
if errors:
raise ValidationError(errors)
class ProjectResource(VerboseNameModelResource):
class Meta:
model = m.Project
exclude = m.Project.get_exclude() + TIMESTAMP_FIELDS
def dehydrate_部门(self, obj):
return obj.department.name
def dehydrate_客户名称(self, obj):
return obj.customer.name
def dehydrate_项目经理(self, obj):
return obj.manager.name
def clean_部门(self, obj, data):
department_name = data['部门'].strip() if data['部门'] else None
if department_name:
department_id = m.Department.objects.get(name=department_name).pk
data['部门'] = department_id
def clean_客户名称(self, obj, data):
customer_name = data['客户名称'].strip() if data['客户名称'] else None
if customer_name:
customer_id = m.Customer.objects.get(name=customer_name).pk
data['客户名称'] = customer_id
def clean_项目经理(self, obj, data):
manager_name = data['项目经理'].strip() if data['项目经理'] else None
if manager_name:
manager_id = m.ProjectManager.objects.get(name=manager_name).pk
data['项目经理'] = manager_id
@JoveCat
Copy link

JoveCat commented Feb 28, 2020

终于找到能用的了,对于外键的也能正确显示verbose_name,但有个问题,用export_order排序的话会报错。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment