导入工作流¶
本文档详细描述了导入数据的工作流程,包含支持自定义导入流程的hooks。
序列图中以黄色高亮显示的方法表示可被重写的公共方法。
import_data() 方法是 Resource 类中负责从给定数据集导入数据的方法。有关该方法的参数,请参阅方法文档。
调用该方法时会发生以下情况:
首先,一个新的: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`了解可用实现。
调用
before_import()钩子。通过在您的资源中实现此方法,可以自定义导入流程。待导入数据集的每一行按照以下步骤处理:
: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()钩子被调用
返回
Result。
事务支持¶
如果启用了事务支持,整个导入过程会被包装在事务中,并相应地回滚或提交。所有从 import_data() 内部调用的方法(创建/删除/更新)都会收到 False 作为 dry_run 参数。