66 lines
2.7 KiB
Python
66 lines
2.7 KiB
Python
from django.core.exceptions import ValidationError
|
|
from django.apps import apps
|
|
|
|
|
|
class ExcelDataSaver:
|
|
def __init__(self, model_name, data):
|
|
app_name, model_name = model_name.split('.')
|
|
self.model = apps.get_model(app_name, model_name)
|
|
self.data = data
|
|
self.field_mapping, self.reverse_field_mapping = self._generate_field_mapping()
|
|
self.errors = []
|
|
|
|
def _generate_field_mapping(self):
|
|
field_mapping = {}
|
|
reverse_field_mapping = {}
|
|
for field in self.model._meta.get_fields():
|
|
if hasattr(field, 'verbose_name'):
|
|
field_mapping[field.verbose_name] = field.name
|
|
reverse_field_mapping[field.name] = field.verbose_name
|
|
return field_mapping, reverse_field_mapping
|
|
|
|
def validate_data(self):
|
|
for row_num, row in enumerate(self.data):
|
|
instance = self.model()
|
|
for field, value in row.items():
|
|
actual_field = self.field_mapping.get(field)
|
|
if not actual_field:
|
|
self.errors.append(f"第【{row_num + 1}】行找不到对应的模型字段: 【{self.reverse_field_mapping[field] + ':' + field}】")
|
|
continue
|
|
setattr(instance, actual_field, value)
|
|
|
|
# 在设置所有字段值之后再调用 full_clean
|
|
try:
|
|
instance.full_clean()
|
|
except ValidationError as e:
|
|
for field, errors in e.message_dict.items():
|
|
for error in errors:
|
|
try:
|
|
self.errors.append(f"第【{row_num + 1}】行【{self.reverse_field_mapping[field]}】字段输入错误: {error}")
|
|
except KeyError:
|
|
self.errors.append(f"第【{row_num + 1}】行,错误原因: {error}")
|
|
except Exception as e:
|
|
self.errors.append(f"其他错误: {e}")
|
|
return len(self.errors) == 0
|
|
|
|
def save_data(self):
|
|
if self.validate_data():
|
|
for row in self.data:
|
|
row_data = {self.field_mapping[field]: value for field, value in row.items() if field in self.field_mapping}
|
|
instance = self.model(**row_data)
|
|
instance.save()
|
|
return True
|
|
return False
|
|
|
|
def get_errors(self):
|
|
return self.errors
|
|
|
|
def add_custom_validation(self, custom_validation_func):
|
|
self.custom_validation_func = custom_validation_func
|
|
self.validate_data = self._validate_data_with_custom
|
|
|
|
def _validate_data_with_custom(self):
|
|
basic_valid = self.validate_data()
|
|
custom_valid = self.custom_validation_func(self.data)
|
|
return basic_valid and custom_valid
|