用于将结构化数据导入 Django 模型的基于 Web 的交互式向导。
项目描述
Django Data Wizard是一个交互式工具,用于通过Django REST Framework和IterTable将表格数据(例如 Excel、CSV、XML、JSON)映射到规范化的数据库结构中。Django Data Wizard 允许新手用户在导入过程中即时将电子表格列映射到序列化器字段(并将单元格值映射到外键)。这减少了对大多数数据导入解决方案所需的预设电子表格格式的需求。
数据向导支持从电子表格列到数据库字段的直接一对一映射,以及更复杂的场景,如自然键和实体-属性-值(或“宽”)表映射。它最初是为与vera提供的ERAV 数据模型一起使用而开发的。
用法
Django Data Wizard 提供了一个Web 界面、JSON API和CLI,用于指定要导入的数据源(例如以前上传的文件)、选择序列化程序、映射数据列和标识符,以及(异步)将数据导入任何目标数据库中的模型。
数据向导旨在允许用户迭代地优化他们的数据导入流程。例如,在初始数据导入期间做出的决定将保留用于将来导入具有相同结构的文件。包含的数据模型使这个工作流程成为可能。
目录
安装
# Recommended: create virtual environment
# python3 -m venv venv
# . venv/bin/activate
python3 -m pip install data-wizard
请参阅https://github.com/wq/django-data-wizard报告任何问题。
初始配置
在新的或现有的 Django 项目中,添加data_wizard
到您的INSTALLED_APPS
:
# myproject/settings.py
INSTALLED_APPS = (
# ...
'data_wizard',
'data_wizard.sources', # Recommended
)
# This can be omitted to use the defaults
DATA_WIZARD = {
'BACKEND': 'data_wizard.backends.threading',
'LOADER': 'data_wizard.loaders.FileLoader',
'IDMAP': 'data_wizard.idmap.existing',
'AUTHENTICATION': 'rest_framework.authentication.SessionAuthentication',
'PERMISSION': 'rest_framework.permissions.IsAdminUser',
'AUTO_IMPORT_TASKS': (
'data_wizard.tasks.check_serializer',
'data_wizard.tasks.check_iter',
'data_wizard.tasks.check_columns',
'data_wizard.tasks.check_row_identifiers',
'data_wizard.tasks.import_data',
),
}
如果你想使用内置的数据源表(FileSource
和URLSource
),也包括data_wizard.sources
在你的INSTALLED_APPS
. 否则,您将需要配置一个或多个自定义数据源(见下文)。
注意:默认情况下,Django 数据向导使用简单的线程后端来执行异步任务。 可以使用Celery 和 Redis代替,但这不是必需的。
接下来,添加"data_wizard.urls"
到您的 URL 配置。
# myproject/urls.py
from django.urls import path, include
urlpatterns = [
# ...
path('datawizard/', include('data_wizard.urls')),
]
目标模型注册
为了使用该向导,您必须注册一个或多个目标模型和/或序列化程序。目标模型注册可帮助向导知道将其在源电子表格的每一行中找到的数据放在何处。(相比之下,只要您使用提供的应用程序,源data_wizard.sources
模型注册是可选的。)
注册 API 仿照 Django admin 和admin.py
. 具体来说,Data Wizard 将wizard.py
在您的应用程序目录中查找一个文件,该文件应具有以下结构:
# myapp/wizard.py
import data_wizard
from .models import MyModel
data_wizard.register(MyModel)
在内部,该向导将自动创建一个与目标模型对应的 Django REST Framework 序列化程序类。如果需要,您还可以指定自定义序列化程序类来配置目标模型的验证和填充方式。
配置完所有内容后,在 Django 管理中上传源文件,从管理操作菜单中选择“通过数据向导导入”,然后浏览下面描述的屏幕。
API 文档
Django 数据向导被实现为一系列视图,可以通过 Django 管理员以及 JSON API 访问。
新运行
POST /datawizard/
创建向导的新实例(即 a Run
)。如果您使用的是 Django 管理集成,则在您从管理操作菜单中选择“通过数据向导导入”时执行此步骤。如果您使用的是 JSON API,则返回的运行id
应用于对该 API 的所有后续调用。每个Run
都通过通用外键绑定到源模型。
范围 | 描述 |
---|---|
object_id |
包含要导入的数据的源模型实例的主键。 |
content_type_id |
源模型的应用标签和模型名称(格式为app_label.modelname )。 |
loader |
(可选)用于通过IterTable加载源数据集的类名。默认 loader( data_wizard.loaders.FileLoader ) 假定源模型包含一个FileField 命名的file . |
serializer |
(可选)填充目标模型时使用的序列化程序类。这可以不设置,以允许用户在向导运行期间选择目标。 |
汽车
POST /datawizard/[id]/auto
该auto
任务尝试从头到尾运行整个数据向导过程。如果需要任何输入,导入将停止并重定向到必要的屏幕。如果不需要输入,则auto
任务相当于data
直接启动任务。这是一个异步方法,并返回一个task_id
用于状态 API 的。
run_detail.html模板提供了一个启动任务的示例表单auto
。auto
任务本身使用run_auto.html模板。
默认任务序列由AUTO_IMPORT_TASKS
设置定义。 注意,check_*
任务不提供直接的 UI 或 HTTP API。data_wizard.InputNeeded
相反,这些任务会在必要时通过引发重定向到相应的 UI 任务。例如,如果电子表格包含意外的列标题,则会data_wizard.tasks.check_columns
引发InputNeeded
并重定向到列任务。提交表单后,updatecolumns任务会处理用户输入并再次运行检查。一旦检查成功(即所有列都已映射),用户就可以重新启动自动任务。
以下是默认顺序中每个任务对应的输入和表单处理任务:
自动任务 | 输入任务 | 表单处理任务 |
---|---|---|
check_serializer |
list_serializers |
updateserializer |
check_iter |
不适用 | 不适用 |
check_columns |
read_columns |
update_columns |
check_row_identifiers |
read_row_identifiers |
update_row_identifiers |
import_data |
不适用 | 不适用 |
有关自定义任务序列的详细信息,请参阅自定义任务。
地位
GET /datawizard/[id]/status.json?task=[task]
该status
API 用于检查异步任务的状态(auto
或之一data
)。提供的data_wizard/js/progress.js使用该 API来更新run_auto.html和run_data.html模板<progress>
中的栏。与其他方法不同,此 API 仅 JSON 且没有 HTML 等效项。将返回以下格式的对象:
{
// General properties
"status": "PROGRESS", // or "SUCCESS", "FAILURE"
"stage": "meta", // or "data"
"current": 23, // currently processing row
"total": 100, // total number of rows
// "FAILURE"
"error": "Error Message",
// Task complete ("SUCCESS")
"action": "records", // or "serializers", "columns" "ids"
"message": "Input Needed", // if action is not "records"
"skipped": [...], // rows that could not be imported
"location": "/datawizard/[id]/records",
}
该 status
字段的潜在值与常见的Celery 任务状态相同,即使不使用celery
后端也是如此。运行auto
任务时,SUCCESS
只要任务没有错误地结束,即使需要额外的输入来完全完成运行,结果也是如此。
默认的run_auto.html和run_data.html模板包含一个<progress>
用于状态任务的元素。
序列化器
GET /datawizard/[id]/serializers
该serializers
任务提供了所有已注册序列化程序(即目标模型)的列表。auto
如果在创建序列化程序时未指定序列化程序,则任务会显示此屏幕Run
。默认的run_serializers.html模板包括一个用于选择目标的界面。如果已经选择了序列化程序,模板将显示标签和一个按钮来(重新)启动auto
任务。
更新序列化程序
POST /datawizard/[id]/updateserializer
该updateserializer
任务Run
使用选定的目标序列化程序名称更新指定。这通常从任务生成的表单serializers
中调用,并在完成时重定向到该任务。
范围 | 描述 |
---|---|
serializer |
用于此运行的目标序列化程序的类名(或标签)。 |
列
GET /datawizard/[id]/columns
该columns
任务列出了在源数据集(即电子表格)中找到的所有列以及它们到目标序列化器字段的映射。auto
如果有任何列名无法自动映射,则任务会显示此屏幕。潜在的映射是以下之一:
- 简单的序列化器字段名称(例如
field
) - 嵌套字段名称(用于自然键,例如
nested[record][field]
) - EAV属性值映射(例如
values[][value];attribute_id=1
)。请注意,EAV 支持需要自定义序列化程序类。
默认的run_columns.html模板包含一个用于将数据列映射到序列化器字段的接口。如果所有列都已映射,则模板将显示映射和用于(重新)启动auto
任务的按钮。
更新列
POST /datawizard/[id]/updatecolumns
该updatecolumns
任务保存从源数据列到目标序列化器字段的指定映射。这通常从任务生成的表单columns
中调用,并在完成时重定向到该任务。
范围 | 描述 |
---|---|
rel_[relid] |
要映射到指定序列化器字段的列。任务relid 将提供可能映射的完整列表。columns |
身份证
GET /datawizard/[id]/ids
该ids
任务列出了在源数据集(即电子表格)中找到的所有外键值。如果有任何未映射的外键值,自动任务将停止并重定向到该ids
任务。默认的run_ids.html模板包括一个用于将行标识符映射到外键值的接口。潜在的映射取决于用于表示外键的序列化器字段。
- 对于PrimaryKeyRelatedField、SlugRelatedField和NaturalKeySerializer,选择将包括所有现有记录 ID 或 slug。
- For
NaturalKeySerializer
only,"new"
还将包括一个选择,允许在外部表中动态创建新记录。
映射完所有 id 后,模板将显示映射和一个用于(重新)启动auto
任务的按钮。
请注意,如果以下任何一项为真,则该auto
任务将完全跳过该ids
任务:
- 该文件不包含外键列
- 在上一次导入运行期间已映射所有外键值
- 所有外键值都可以通过
DATA_WIZARD['IDMAP']
设置自动映射:
DATA_WIZARD['IDMAP'] |
细节 |
---|---|
"data_wizard.idmap.existing" (默认) |
自动映射现有 ID,但需要用户映射未知 ID |
"data_wizard.idmap.never" |
要求用户在文件中第一次找到所有 ID 时手动映射它们 |
"data_wizard.idmap.always" |
始终映射 ID(跳过手动映射)。未知 ID 将按原样传递给序列化程序,这将导致每行错误,除非使用自然键。 |
(自定义导入路径) | 该函数应该接受一个标识符和一个序列化器字段,并返回映射的值(或者None 如果没有自动映射可用)。有关示例,请参见内置函数。 |
请注意,配置的IDMAP
函数只会在第一次遇到新标识符时被调用。一旦建立映射(手动或自动),它将在后续的向导运行中重新使用。
更新ID
POST /datawizard/[id]/updateids
该updateids
任务保存从行标识符到外键值的指定映射。这通常从任务生成的表单ids
中调用,并在完成时重定向到该任务。
范围 | 描述 |
---|---|
ident_[identid]_id |
要映射到指定外键值的标识符。任务identid 将提供可能映射的完整列表。ids |
数据
POST /datawizard/[id]/data
该data
任务启动实际的导入过程(并auto
在幕后调用)。与 不同的是,如果需要任何元输入auto
,直接调用data
不会导致重定向到其他任务之一。相反,data
将尝试按原样导入每条记录,并报告由于例如缺少字段或未映射的外键而发生的任何错误。
这是一个异步方法,并返回一个task_id
用于status
API 的方法。默认的run_data.html模板包含一个<progress>
用于状态任务的元素。
记录
GET /datawizard/[id]/records
该records
任务提供导入行的列表(包括错误)。完成后由auto
and任务重定向到。data
成功导入Record
的实例将具有指向目标模型的通用外键。该records
任务将包含指向get_absolute_url()
每个新导入的目标模型实例的管理屏幕的链接。默认的run_records.html模板包含一个用于显示记录详细信息的界面。
运行列表
GET /datawizard/
Django 数据向导提供了一个列表视图,它总结了以前的运行和每次导入的记录数。也可以从此列表重新启动未完成的运行。
标识符管理员
GET /admin/data_wizard/identifer/
可以通过 Django Admin 查看和编辑 Django 数据向导标识符映射。运行也可以通过管理员查看 - 尽管上面的运行列表通常会更有用。
数据模型
Django Data Wizard 提供了许多 Django 模型来帮助跟踪导入过程,并保留数据映射决策以供将来重用。虽然需要源模型,但您的目标数据模型通常无需更改即可支持数据向导集成。
步 | 描述 | 模型 |
---|---|---|
0 | 上传源文件 | 创建FileSource (或自定义源模型) |
1 | 开始数据向导运行 | 创造Run |
2 | 选择序列化程序(和目标模型) | 更新Run |
3 | 将列映射到数据库字段名称 | Identifier 如果需要,每列一个 |
4 | 将单元格值映射到外键 | Identifier 每个唯一值一个 |
5 | 将数据导入目标模型 | 每行一个Record + 一个目标模型实例 |
该Run
模型包括一个指向源模型的通用外键FileSource
(例如。)源电子表格中的每一行都将映射到一个Record
. 如果成功导入该行,将创建目标数据模型的新实例,并且Record
将有一个指向它的通用外键。该Identifier
模型不包含外键,因为标识符映射被重复用于后续导入。相反,一个单独的模型跟踪 each中每个Range
的位置(行/列)。Identifier
Run
请注意,上述工作流程仅描述了最常见的用例。您可以创建自定义序列化程序,为每个电子表格行更新多个目标数据模型。您可以指定可能不是电子表格甚至文件的自定义数据源。
命令行界面
Django Data Wizard 提供了一个单一的管理命令,runwizard
,可用于auto
从命令行启动任务。这可用于促进自动化处理,例如作为常规 cron 作业的一部分。请注意,CLI(当前)不支持交互式映射列和 ID,因此应使用 Web 或 JSON API 预先映射这些列和 ID。
用法:
./manage.py runwizard myapp.mymodel 123 \
--loader myapp.loaders.customloader \
--serializer myapp.serializer.customserializer \
--username myusername
基本用法与New Run API类似。仅需要内容类型和对象 ID,而其他参数将在可能的情况下自动检测。特别是,您可能希望使用set_loader()来预定义默认值loader
以及serializer
您计划与 CLI 一起使用的任何模型。
该runwizard
命令将创建一个新的Run
并立即启动该auto
任务。错误将显示在控制台上。
自定义序列化器
数据向导使用 Django REST Framework 的Serializer 类的实例来确定目标模型上的目标字段。具体来说,默认的序列化器是NaturalKeyModelSerializer,它基于ModelSerializer。
data_wizard.register()
您可以通过使用名称和序列化程序类而不是模型类调用来覆盖默认序列化程序。可以使用向导注册多个序列化程序以支持多个导入配置和目标模型。
# myapp/wizard.py
from rest_framework import serializers
import data_wizard
from .models import TimeSeries
class TimeSeriesSerializer(serializers.ModelSerializer):
# (custom fields here)
class Meta:
model = TimeSeries
fields = '__all__'
# Optional - see options below
data_wizard = {
'header_row': 0,
'start_row': 1,
'show_in_list': True,
'idmap': data_wizard.idmap.existing,
'auto_import_tasks': [ custom task list ],
}
# Use default name & serializer
data_wizard.register(TimeSeries)
# Use custom name & serializer
data_wizard.register("Time Series - Custom Serializer", TimeSeriesSerializer)
至少应注册一个序列化程序或模型才能使用该向导。请注意在注册序列化程序时使用人性化的序列化程序标签。此名称在整个项目中应该是唯一的,但以后可以在不破坏现有数据的情况下进行更改。(类路径用作幕后的实际标识符。)
串行器选项
通常,自定义序列化程序具有常规Django REST 框架序列化程序的所有功能,包括自定义验证规则和填充多个目标模型的能力。虽然request
上下文不可用,但可以通过上下文检索有关运行(包括用户)的信息data_wizard
。
当为自然键模型重写序列化器时,一定要扩展NaturalKeyModelSerializer,如本例所示。在其他情况下,扩展ModelSerializer(如上例所示)或基本Serializer类。
自定义序列化程序可用于支持实体-属性-值电子表格,其中属性名称被指定为附加列。为了支持这种情况,Entity
序列化程序应该包含一个嵌套的Value
序列化程序many=True
,并且Value
序列化程序应该有一个表的外键Attribute
,如本例所示。
数据向导还通过在序列化程序的类data_wizard
上设置属性来支持其他配置。Meta
支持以下选项。
姓名 | 默认 | 笔记 |
---|---|---|
header_row |
0 | 指定包含列标题的电子表格的第一行。如果该值大于 0,则将扫描列标题上方的空间以查找任何看起来像一次性“全局”值的内容,该值旨在应用于导入数据中的每一行。 |
start_row |
1 | 第一行数据。如果大于header_row + 1 ,则假定列标题跨越多行。一个常见的情况是 EAV 参数名称在第一行,单位在第二行。 |
show_in_list |
True |
如果设置为False ,序列化程序将通过 API 可用,但不会在向导视图中列出。如果您有一个仅应在完全自动化的工作流程中使用的序列化程序,这将非常有用。 |
idmap |
IDMAP 环境 |
可以是任何data_wizard.idmap.* 函数或自定义函数。与IDMAP 设置不同,这应该始终是实际功能,而不是导入路径。 |
auto_import_tasks |
AUTO_IMPORT_TASKS 环境 |
注册函数的导入路径列表@data_wizard.wizard_task (请参阅自定义任务。 |
自定义数据源
Django Data Wizard 使用IterTable来确定电子表格或其他数据源中存在的源列。Django Data Wizard 可以使用任何 Django 模型实例作为其数据的源,只要有一个注册的加载器可以将源模型转换为Iter 类。Data Wizard 提供了两个开箱即用的加载器FileLoader和URLLoader,它们可以分别与data_wizard.sources
(FileSource
和URLSource
) 中提供的模型一起使用。
扩展文件加载器
默认值FileLoader
可用于任何具有FileField
命名的 Django 模型file
。FileField
您可以通过创建一个子类data_wizard.loaders.FileLoader
并将其设置为模型的加载器来使用具有不同名称的模型。
# myapp/models.py
from django.db import models
class FileModel(models.Model):
spreadsheet = models.FileField(upload_to='spreadsheets')
# myapp/loaders.py
from data_wizard import loaders
class FileLoader(loaders.FileLoader):
file_attr = 'spreadsheet'
# myapp/wizard.py
import data_wizard
from .models import FileModel
data_wizard.set_loader(FileModel, "myapp.loaders.FileLoader")
如果您有一个可以处理多个源模型的通用加载器,您还可以全局设置默认加载器:
# myapp/settings.py
DATA_WIZARD = {
'LOADER': 'myapp.loaders.FileLoader'
}
您应该注册一个自定义ModelAdmin
类以在您的模型的管理面板中添加导入操作。
# myapp/admin.py
from django.contrib import admin
from data_wizard.admin import ImportActionModelAdmin
from .models import FileModel
@admin.register(FileModel)
class FileModelAdmin(ImportActionModelAdmin):
pass
自定义加载器
默认加载器支持IterTable支持的任何文件格式(Excel、CSV、JSON 和 XML)。可以通过创建自定义 IterTable 类然后将其注册到向导来集成其他格式。例如,Climata 查看器使用 Django 数据向导从climata的基于 IterTable 的 Web 服务客户端导入数据。为此,请使用从 IterTable 返回数据data_wizard.loaders.BaseLoader
的自定义load_iter()
函数进行扩展,如下例所示。
您可能希望在自定义加载程序中使用特定的序列化程序。如果是这样,请覆盖default_serializer
或get_serializer_name()
在加载程序上。默认情况下,这些返回None
,这需要用户在创建或执行时指定序列化程序Run
。
# myapp/models.py
from django.db import models
class CustomIterSource(models.Model):
some_option = models.TextField()
# myapp/loaders.py
from data_wizard import loaders
from .iter import CustomIter
class CustomIterLoader(loaders.BaseLoader):
default_serializer = 'mydataapp.wizard.CustomSerializer'
def load_iter(self):
source = self.run.content_object
return CustomIter(some_option=source.some_option)
# myapp/wizard.py
import data_wizard
from .models import CustomIterSource
data_wizard.set_loader(CustomIterSource, "myapp.loaders.CustomIterLoader")
自定义任务
可以覆盖自动任务执行的任务序列,删除步骤或添加新步骤。该列表可以被全局覆盖(通过设置DATA_WIZARD['AUTO_IMPORT_TASKS']
),或者基于每个序列化器(通过设置Meta.data_wizard['auto_import_tasks']
)。
每个自定义任务函数都应该向@data_wizard.wizard_task
装饰器注册,以配置标签和可选的 API 路径相对于/datawizard/[id]/
. 装饰器和函数的参数决定了任务类型。
检查任务
@data_wizard.wizard_task(label="Custom Check", url_path=False)
def custom_check(run):
if not some_condition_satisfied(run):
raise data_wizard.InputNeeded("custominput")
检查任务验证是否满足某些条件,如果需要,重定向到输入任务。 url_path
通常设置为 False 以禁用 HTTP 端点。任务标签将显示在进度条中(如果任务运行时间超过几秒钟)。
输入任务
@data_wizard.wizard_task(label="Custom Input", url_path="custominput")
def custom_input(run):
return {"some_template_context": []}
输入任务使用户能够提供反馈以指导向导。它们应该有一个url_path
(默认为函数名)和一个相应的模板(例如data_wizard/run_custominput.html
)。任务返回的上下文将在result
变量下的模板中。该模板通常会呈现带有所需输入的表单,或者(如果已输入所有输入)带有重新启动自动任务选项的摘要。
表单处理任务
@data_wizard.wizard_task(label="Custom Input", url_path="customsave")
def custom_save(run, post={}):
some_save_method(run, post)
return {
**custom_input(run),
"current_mode": "custominput",
}
表单处理任务处理从先前输入任务提交的表单。注册类似于输入任务,除了函数本身应该接受一个可选的post
kwarg。表单处理任务应该注册url_path
,并重定向回输入任务(通过设置current_mode
响应)。
自定义自动任务
在非常高级的用例中,可能需要根据许多因素动态生成任务列表。在这种情况下,可以定义一个完全自定义的自动任务:
@data_wizard.wizard_task(label="Custom Workflow", url_path="customauto", use_async=True)
def custom_auto(run):
task_list = somehow_determine_tasks(run)
return run.run_all(task_list)
注册与其他任务类似,加了use_async
关键字,方便通过配置的任务后端进行后台处理。
一般来说,自动化任务列表中的任务应该是检查任务或其他自动任务。输入和表单处理任务应在自动化流程之外执行。
任务后端
可以通过BACKEND
设置配置以下任何后端:
# myproject/settings.py
DATA_WIZARD = {
"BACKEND": "data_wizard.backends.threading" # Default
"data_wizard.backends.immediate"
"data_wizard.backends.celery"
}
data_wizard.backends.threading
threading
后端为长时间运行的异步任务(即auto
和data
)创建一个单独的线程。线程后端利用 Django 缓存将结果传递回状态 API。这是默认后端,但明确设置它仍然是一个好主意。
data_wizard.backends.immediate
后端在将immediate
结果返回给客户端之前完成所有处理,即使对于其他“异步”任务(auto
和data
)也是如此。此后端适用于小型电子表格,或用于解决线程问题。此后端保持最小状态,不建议用于涉及大型电子表格或多个同时导入过程的用例。
data_wizard.backends.celery
celery
后端利用Celery处理异步任务,通常与Redis一起用作内存存储。默认情况下,这些附加依赖项不会随 Django 数据向导一起安装。如果要