问题描述
我在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
中的ImportExportModelAdmin
的get_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的导入表单以为每个导入的行指定固定值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!