Last active
February 28, 2020 13:44
-
-
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 字段值
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
终于找到能用的了,对于外键的也能正确显示verbose_name,但有个问题,用export_order排序的话会报错。