扩展django-import-export的导入表单以为每个导入的行指定固定值 [英] Extend django-import-export's import form to specify fixed value for each imported row

查看:213
本文介绍了扩展django-import-export的导入表单以为每个导入的行指定固定值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Django 2.1.1中将django-import-export 1.0.1与管理员集成在一起使用.我有两个模型

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

from django.db import models

class Sector(models.Model):
    code = models.CharField(max_length=30, primary_key=True)

class Location(models.Model):
    code = models.CharField(max_length=30, primary_key=True)
    sector = ForeignKey(Sector, on_delete=models.CASCADE, related_name='locations')

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

and they can be imported/exported just fine using model resources

from import_export import resources
from import_export.fields import Field
from import_export.widgets import ForeignKeyWidget

class SectorResource(resources.ModelResource):
    code = Field(attribute='code', column_name='Sector')
    class Meta:
        model = Sector
        import_id_fields = ('code',)

class LocationResource(resources.ModelResource):
    code = Field(attribute='code', column_name='Location')
    sector = Field(attribute='sector', column_name='Sector',
                   widget=ForeignKeyWidget(Sector, 'code'))
    class Meta:
        model = Location
        import_id_fields = ('code',)

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

and import/export actions can be integrated into the admin by

from django.contrib import admin
from import_export.admin import ImportExportModelAdmin

class SectorAdmin(ImportExportModelAdmin):
    resource_class = SectorResource

class LocationAdmin(ImportExportModelAdmin):
    resource_class = LocationResource

admin.site.register(Sector, SectorAdmin)
admin.site.register(Location, LocationAdmin)

对于 Reasons™,我想更改此设置,以便可以导入包含Sector列的Locations电子表格; sector的值(对于每个导入的行)应取自管理员ImportForm上的额外字段.

For Reasons™, I would like to change this set-up so that a spreadsheet of Locations which does not contain a Sector column can be imported; the value of sector (for each imported row) should be taken from an extra field on the ImportForm in the admin.

确实可以通过覆盖ModelAdmin上的import_action来添加这样的字段,如扩展django的管理员导入表单中所述import_export .下一步,要在所有导入的行中使用此值,在那里丢失了,我还无法弄清楚该怎么做.

Such a field can indeed be added by overriding import_action on the ModelAdmin as described in Extending the admin import form for django import_export. 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.

推荐答案

EDIT(2):通过使用会话解决.拥有get_confirm_import_form钩子对 still 确实很有帮助,但更好的做法是让现有的ConfirmImportForm跨所有提交的字段&初始导入表单中的值.

EDIT(2): Solved through the use of sessions. Having a get_confirm_import_form hook would still really help here, but even better would be having the existing ConfirmImportForm carry across all the submitted fields & values from the initial import form.

编辑:很抱歉,我以为我已经钉上了这个钉子,但是我自己的代码无法正常工作.此不会解决在ConfirmImportForm中传递sector form字段的问题,这对于完成导入是必不可少的.当前正在寻找一种不涉及将整个import_action()粘贴到ImportMixin子类中的解决方案.拥有get_confirm_import_form()钩子在这里会大有帮助.

I'm sorry, I thought I had this nailed, but my own code wasn't working as well as I thought it was. This doesn't solve the problem of passing along the sector form field in the ConfirmImportForm, which is necessary for the import to complete. Currently looking for a solution which doesn't involve pasting the whole of import_action() into an ImportMixin subclass. Having a get_confirm_import_form() hook would help a lot here.

仍然会为自己制定一种解决方案,当我有一个解决方案时,我也会对其进行更新.

Still working on a solution for myself, and when I have one I'll update this too.

请勿覆盖import_action.这是您不想复制的复杂方法.更重要的是,正如我今天发现的那样:有更简单的方法可以做到这一点.

Don't override import_action. It's a big complicated method that you don't want to replicate. More importantly, as I discovered today: there are easier ways of doing this.

首先(如前所述),为Location创建一个自定义导入表单,该表单允许用户选择Sector:

First (as you mentioned), make a custom import form for Location that allows the user to choose a Sector:

class LocationImportForm(ImportForm):
    sector = forms.ModelChoiceField(required=True, queryset=Sector.objects.all())

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

In the Resource API, there's a before_import_row() hook that is called once per row. So, implement that in your LocationResource class, and use it to add the Sector column:

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

(注意::该代码使用Django会话将sector值从导入表单携带到导入确认屏幕.如果您不使用会话,则需要查找另一个的方法.)

(Note: This code uses Django sessions to carry the sector value from the import form to the import confirmation screen. If you're not using sessions, you'll need to find another way to do it.)

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

This is all you need to get the extra data in, and it works for both the dry-run preview and the actual import.

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

Note that self.request doesn't exist in the default ModelResource - we have to install it by giving LocationResource a custom constructor:

def __init__(self, request=None):
    super()
    self.request = request

(不必担心self.request会一直存在.每个LocationResource实例都不会在单个请求之后持续存在.)

(Don't worry about self.request sticking around. Each LocationResource instance doesn't persist beyond a single request.)

request通常不传递给ModelResource构造函数,因此我们需要将其添加到该调用的kwargs字典中.幸运的是,Django Import/Export具有专用的挂钩.覆盖LocationAdmin中的ImportExportModelAdminget_resource_kwargs方法:

The request isn't usually passed to the ModelResource constructor, so we need to add it to the kwargs dict for that call. Fortunately, Django Import/Export has a dedicated hook for that. Override ImportExportModelAdmin's get_resource_kwargs method in LocationAdmin:

def get_resource_kwargs(self, request, *args, **kwargs):
    rk = super().get_resource_kwargs(request, *args, **kwargs)
    rk['request'] = request
    return rk

这就是您所需要的.

这篇关于扩展django-import-export的导入表单以为每个导入的行指定固定值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆