扩展 django-import-export 的导入表单,为每个导入行指定固定值

Ric*_*ing 2 python django django-forms django-admin django-import-export

I am using django-import-export 1.0.1 with admin integration in Django 2.1.1. I have two models

\n\n
from django.db import models\n\nclass Sector(models.Model):\n    code = models.CharField(max_length=30, primary_key=True)\n\nclass Location(models.Model):\n    code = models.CharField(max_length=30, primary_key=True)\n    sector = ForeignKey(Sector, on_delete=models.CASCADE, related_name=\'locations\')\n
Run Code Online (Sandbox Code Playgroud)\n\n

并且可以使用模型资源很好地导入/导出它们

\n\n
from import_export import resources\nfrom import_export.fields import Field\nfrom import_export.widgets import ForeignKeyWidget\n\nclass SectorResource(resources.ModelResource):\n    code = Field(attribute=\'code\', column_name=\'Sector\')\n    class Meta:\n        model = Sector\n        import_id_fields = (\'code\',)\n\nclass LocationResource(resources.ModelResource):\n    code = Field(attribute=\'code\', column_name=\'Location\')\n    sector = Field(attribute=\'sector\', column_name=\'Sector\',\n                   widget=ForeignKeyWidget(Sector, \'code\'))\n    class Meta:\n        model = Location\n        import_id_fields = (\'code\',)\n
Run Code Online (Sandbox Code Playgroud)\n\n

导入/导出操作可以通过以下方式集成到管理中

\n\n
from django.contrib import admin\nfrom import_export.admin import ImportExportModelAdmin\n\nclass SectorAdmin(ImportExportModelAdmin):\n    resource_class = SectorResource\n\nclass LocationAdmin(ImportExportModelAdmin):\n    resource_class = LocationResource\n\nadmin.site.register(Sector, SectorAdmin)\nadmin.site.register(Location, LocationAdmin)\n
Run Code Online (Sandbox Code Playgroud)\n\n

由于Reasons\xe2\x84\xa2,我想更改此设置,以便可以导入不包含扇区列的Locations电子表格;(对于每个导入的行)的值sector应该从额外的字段中获取ImportForm in the admin.

\n\n

确实可以通过覆盖扩展 django import_export 的管理导入表单中所述的方式import_action来添加这样的字段ModelAdmin. The next step, to use this value for all imported rows, is missing there, and I have not been able to figure out how to do it.

\n

yoz*_*yoz 6

编辑(2):通过使用会话解决。拥有一个get_confirm_import_form钩子在这里仍然很有帮助,但更好的是让现有的ConfirmImportForm进位跨越初始导入表单中所有提交的字段和值。

编辑:抱歉,我以为我已经解决了这个问题,但我自己的代码并没有像我想象的那样工作。这并不能解决sector在 中传递表单字段的问题ConfirmImportForm,而这是完成导入所必需的。目前正在寻找一种不涉及将整个粘贴import_action()ImportMixin子类中的解决方案。在这里有一个get_confirm_import_form()钩子会有很大帮助。

仍在为自己寻找解决方案,当我有了解决方案时,我也会更新它。


不要覆盖import_action. 这是一个非常复杂的方法,您不想重复。更重要的是,正如我今天发现的:有更简单的方法可以做到这一点。

首先(正如您所提到的),创建一个自定义导入表单,Location允许用户选择Sector

class LocationImportForm(ImportForm):
    sector = forms.ModelChoiceField(required=True, queryset=Sector.objects.all())
Run Code Online (Sandbox Code Playgroud)

在资源 API 中,有一个before_import_row()每行调用一次的钩子。因此,在您的类中实现它LocationResource,并使用它来添加Sector列:

def before_import_row(self, row, **kwargs):
    sector = self.request.POST.get('sector', None)
    if contract:
        self.request.session['import_context_sector'] = sector
    else:
        # if this raises a KeyError, we want to know about it.
        # It means that we got to a point of importing data without
        # contract context, and we don't want to continue.
        try:
            sector = self.request.session['import_context_sector']
        except KeyError as e:
            raise Exception("Sector context failure on row import, " +
                                 f"check resources.py for more info: {e}")
    row['sector'] = sector
Run Code Online (Sandbox Code Playgroud)

注意:此代码使用 Django 会话将导入表单中的值传送sector到导入确认屏幕。如果您不使用会话,则需要找到另一种方法来执行此操作。)

这就是获取额外数据所需的全部内容,它适用于试运行预览和实际导入。

请注意,self.request默认情况下不存在ModelResource- 我们必须通过提供LocationResource自定义构造函数来安装它:

def __init__(self, request=None):
    super()
    self.request = request
Run Code Online (Sandbox Code Playgroud)

(不用担心会self.request留下来。每个LocationResource实例不会持续超过一个请求。)

通常request不会传递给ModelResource构造函数,因此我们需要将其添加到该调用的 kwargs 字典中。幸运的是,Django Import/Export 有一个专用的钩子。重写ImportExportModelAdminget_resource_kwargs方法LocationAdmin

def get_resource_kwargs(self, request, *args, **kwargs):
    rk = super().get_resource_kwargs(request, *args, **kwargs)
    rk['request'] = request
    return rk
Run Code Online (Sandbox Code Playgroud)

这就是您所需要的。