导入前检查 .csv 文件格式是否正确,避免将错误数据嵌入数据库

Checking if the .csv file is formatted correctly before importing to avoid embedding wrong data into database

我正在开发一个 Django 项目,该项目需要使用以 Excel 表格式提供的批量数据更新数据库。 所以基本上,用户可以上传格式正确的 .csv 文件(我的意思是格式正确,格式正确的文件包含我期望的数据)。我知道如何使用 django-import-export 导入文件,但问题是,我不知道如何执行检查,例如在更新数据库之前检查 .csv 文件是否具有正确的列名和信息。 我是django的新手,请帮忙。

正在检查格式正确的文件

如果您以编程方式导入文件,那么如果您可以 load a Dataset object 且不会出现任何错误,则它是一个 well-formed csv 文件。所以像这样:

try:
  with open('data.csv', 'r') as fh:
    imported_data = Dataset().load(fh, headers=False)
except Exception as e:
  # you can add additional error handling / logging here if you like
  print("import fail")
  raise e

检查是否正确 headers

在导入过程之前,您可以使用 a hook 来检查 headers 是否有效。所以你可以做类似下面的事情来检查丢失的列:

class YourResource(resources.ModelResource):
    fields = ('author', 'email')

    def before_import(self, dataset, using_transactions, dry_run, **kwargs):
        for field_name in self.fields:
            col_name = self.fields[field_name].column_name
            if col_name not in dataset.headers:
                raise ValueError(f"'{col_name}' field not in data file")

数据验证

您可以使用 in-built widgets 在字段级别提供额外的验证。您可以根据需要扩展它们以启用额外的 domain-specific 验证。例如,如果您只想允许“1”或“0”作为您的布尔值,您可以执行以下操作:

class StrictBooleanWidget(widgets.BooleanWidget):
    TRUE_VALUES = ["1"]
    FALSE_VALUES = ["0"]
    NULL_VALUES = [""]

    def clean(self, value, row=None, *args, **kwargs):
        if value in self.NULL_VALUES:
            return None
        if value in self.TRUE_VALUES:
            return True
        if value in self.FALSE_VALUES:
            return False
        raise ValueError("Invalid boolean: value must be 1 or 0.")

然后在您的资源中参考这个:

class YourResource(resources.ModelResource):
    is_active = fields.Field(
        attribute="active",
        column_name="active",
        default=False,
        widget=upload.widgets.StrictBooleanWidget(),
    )

您还可以使用此方法检查数据中是否存在缺失值或空值。

django-import-export 确实对您描述的 use-case 有很大帮助,但是当您不熟悉它时可能会感到困惑。深入阅读文档,我建议下载 运行 example application(如果你还没有的话)。

核心导入逻辑相当简单,但如果您可以在开发过程中设置断点并单步执行,将会节省大量时间。这将真正帮助您了解正在发生的事情。