导入工作流

本文档详细描述了导入数据的工作流程,包含支持自定义导入流程的hooks。

序列图中以黄色高亮显示的方法表示可被重写的公共方法。

导入工作流程序列图

import_data() 方法是 Resource 类中负责从给定数据集导入数据的方法。有关该方法的参数,请参阅方法文档。

调用该方法时会发生以下情况:

  1. 首先,一个新的:class:`~import_export.results.Result`实例被初始化,该实例保存了导入过程中收集的错误和其他信息。

    然后,初始化负责加载现有实例的:class:~import_export.instance_loaders.BaseInstanceLoader。可以通过:class:~import_export.options.ResourceOptions`的``instance_loader_class``属性指定不同的:class:`~import_export.instance_loaders.BaseInstanceLoader。可以使用:class:`~import_export.instance_loaders.CachedInstanceLoader`来减少数据库查询次数。查看:mod:`~import_export.instance_loaders`了解可用实现。

  2. 调用 before_import() 钩子。通过在您的资源中实现此方法,可以自定义导入流程。

  3. 待导入数据集的每一行按照以下步骤处理:

    • :meth:`~import_export.resources.Resource.before_import_row 钩子被调用以允许在导入前修改行数据。

    • get_or_init_instance() 被调用时传入当前的 BaseInstanceLoader 和数据集当前行,返回一个对象和一个布尔值,声明该对象是否为新创建的。

      如果找不到当前行的对象,则调用:meth:`~import_export.resources.Resource.init_instance`来初始化一个对象。

      一如既往,你可以重写 init_instance() 的实现来自定义新对象的创建方式(例如设置默认值)。

    • for_delete() 被调用来确定是否应删除传入的 instance。在这种情况下,当前行的导入过程会在此处停止。

    • 如果实例未在上一步骤中删除,则使用当前对象实例的 instance 和当前行的 row 调用 import_row()

      import_field() 会为 Resource 中的每个字段调用,跳过多对多字段。多对多字段被跳过是因为它们要求实例具有主键,因此赋值被推迟到对象已经保存之后。

      import_field() 接着会调用 save(),如果 Field.attribute 已设置且 Field.column_name 存在于给定行中。

    • 然后确定新导入的对象是否与已存在的对象不同,从而决定是否应跳过给定行。这是通过调用 skip_row() 来处理的,其中 original 为原始对象,instance 为数据集中的当前对象。

      如果当前行需要跳过,row_result.import_type 将被设置为 IMPORT_TYPE_SKIP

    • 如果当前行未被跳过,则调用:meth:`~import_export.resources.Resource.save_instance`并在未设置``dry_run``时实际保存实例。

      有两种钩子方法(默认情况下不执行任何操作)让您可以选择自定义导入过程:

    • save_m2m() 被调用来保存多对多字段。

    • RowResult 被分配了原始对象字段与导入对象字段之间的差异,以及一个 import_type 属性,该属性声明该行是新增、更新、跳过还是删除。

      如果在行处理期间引发异常且调用 import_row() 时设置了 ``raise_errors=False``(默认值),则特定追溯信息也会附加到 RowResult 中。

      如果行未被跳过或:class:`~import_export.resources.Resource`配置为报告跳过的行,则:class:`~import_export.results.RowResult`会被附加到:class:`~import_export.results.Result`中

    • after_import_row() 钩子被调用

  4. 返回 Result

事务支持

如果启用了事务支持,整个导入过程会被包装在事务中,并相应地回滚或提交。所有从 import_data() 内部调用的方法(创建/删除/更新)都会收到 False 作为 dry_run 参数。