![CSV CSV](https://c1.lmlphp.com/image/static/default_avatar.gif)
本文介绍了将 django-import-export 与基于类的视图一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我想将 django-import-export
与基于类的视图一起使用.
在 https://django-import-export 的文档中.readthedocs.org/en/latest/getting_started.html 我看到了一个导出为 csv 的例子
>>>数据集 = BookResource().export()>>>打印数据集.csvID、名称、作者、author_email、导入、已发布、价格、类别2,某本书,1,,0,2012-12-05,8.85,1但是如果我想返回一个 Excel 文件,我应该使用哪个基于类的视图?只是查看
?
解决方案
Jamgreen,
基于 https://github.com/bmihelac/django-import-export 的实施并考虑一个模型国家"作为示例,名称和缩写属性:
首先,在 Country 模型文件的末尾定义资源:
class CountryResource(resources.ModelResource):元类:型号 = 国家
然后,实现基于类的视图:
class CountryExport(View):def get(self, *args, **kwargs):数据集 = CountryResource().export()响应 = HttpResponse(dataset.csv, content_type="csv")response['Content-Disposition'] = '附件;文件名=文件名.csv'返回响应类 CountryImport(查看):型号 = 国家from_encoding = "utf-8"#:导入/导出格式DEFAULT_FORMATS = (base_formats.CSV,base_formats.XLS,base_formats.TSV,base_formats.ODS,base_formats.JSON,base_formats.YAML,base_formats.HTML,)格式 = DEFAULT_FORMATS#: 导入视图模板import_template_name = '国家/地区/import.html'资源类 = 无def get_import_formats(self):"""返回可用的导入格式."""return [f for f in self.formats if f().can_import()]def get_resource_class(self):如果不是 self.resource_class:返回模型资源工厂(self.model)别的:返回 self.resource_classdef get_import_resource_class(self):"""返回用于导入的 ResourceClass."""返回 self.get_resource_class()def get(self, *args, **kwargs):'''执行导入的 dry_run 以确保导入不会导致错误.如果没有错误,保存用户上传文件到本地临时文件,该文件将被使用'process_import' 用于实际导入.'''资源 = self.get_import_resource_class()()上下文 = {}import_formats = self.get_import_formats()form = ImportForm(import_formats,self.request.POST 或 None,self.request.FILES 或 None)如果 self.request.POST 和 form.is_valid():输入格式 = 导入格式[int(form.cleaned_data['input_format'])]()import_file = form.cleaned_data['import_file']# 首先总是将上传的文件写入磁盘,因为它可能是# 内存文件或其他基于设置上传处理程序使用 tempfile.NamedTemporaryFile(delete=False) 作为上传文件:对于 import_file.chunks() 中的块:upload_file.write(块)# 然后使用正确的特定格式模式读取文件随着打开(uploaded_file.name,input_format.get_read_mode()) 作为uploaded_import_file:# 警告,大文件可能超出内存数据 = Uploaded_import_file.read()如果不是 input_format.is_binary() 和 self.from_encoding:数据 = force_text(数据,self.from_encoding)数据集 = input_format.create_dataset(data)结果 = resource.import_data(数据集,dry_run=True,raise_errors=False)上下文['结果'] = 结果如果不是 result.has_errors():上下文['confirm_form'] = ConfirmImportForm(initial={'import_file_name': os.path.basename(uploaded_file.name),'input_format': form.cleaned_data['input_format'],})上下文['形式'] = 形式context['opts'] = self.model._metacontext['fields'] = [f.column_name for f in resource.get_fields()]返回模板响应(self.request,[self.import_template_name],上下文)def post(self, *args, **kwargs):'''执行导入的 dry_run 以确保导入不会导致错误.如果没有错误,保存用户上传文件到本地临时文件,该文件将被使用'process_import' 用于实际导入.'''资源 = self.get_import_resource_class()()上下文 = {}import_formats = self.get_import_formats()form = ImportForm(import_formats,self.request.POST 或 None,self.request.FILES 或 None)如果 self.request.POST 和 form.is_valid():输入格式 = 导入格式[int(form.cleaned_data['input_format'])]()import_file = form.cleaned_data['import_file']# 首先总是将上传的文件写入磁盘,因为它可能是# 内存文件或其他基于设置上传处理程序使用 tempfile.NamedTemporaryFile(delete=False) 作为上传文件:对于 import_file.chunks() 中的块:upload_file.write(块)# 然后使用正确的特定格式模式读取文件随着打开(uploaded_file.name,input_format.get_read_mode()) 作为uploaded_import_file:# 警告,大文件可能超出内存数据 = Uploaded_import_file.read()如果不是 input_format.is_binary() 和 self.from_encoding:数据 = force_text(数据,self.from_encoding)数据集 = input_format.create_dataset(data)结果 = resource.import_data(数据集,dry_run=True,raise_errors=False)上下文['结果'] = 结果如果不是 result.has_errors():上下文['confirm_form'] = ConfirmImportForm(initial={'import_file_name': os.path.basename(uploaded_file.name),'input_format': form.cleaned_data['input_format'],})上下文['形式'] = 形式context['opts'] = self.model._metacontext['fields'] = [f.column_name for f in resource.get_fields()]返回模板响应(self.request,[self.import_template_name],上下文)类 CountryProcessImport(View):型号 = 国家from_encoding = "utf-8"#:导入/导出格式DEFAULT_FORMATS = (base_formats.CSV,base_formats.XLS,base_formats.TSV,base_formats.ODS,base_formats.JSON,base_formats.YAML,base_formats.HTML,)格式 = DEFAULT_FORMATS#: 导入视图模板import_template_name = '国家/地区/import.html'资源类 = 无def get_import_formats(self):"""返回可用的导入格式."""return [f for f in self.formats if f().can_import()]def get_resource_class(self):如果不是 self.resource_class:返回模型资源工厂(self.model)别的:返回 self.resource_classdef get_import_resource_class(self):"""返回用于导入的 ResourceClass."""返回 self.get_resource_class()def post(self, *args, **kwargs):'''执行实际的导入操作(在用户确认他希望进口)'''opts = self.model._meta资源 = self.get_import_resource_class()()Confirm_form = ConfirmImportForm(self.request.POST)如果confirm_form.is_valid():import_formats = self.get_import_formats()输入格式 = 导入格式[int(confirm_form.cleaned_data['input_format'])]()import_file_name = os.path.join(tempfile.gettempdir(),Confirm_form.cleaned_data['import_file_name'])import_file = open(import_file_name, input_format.get_read_mode())数据 = import_file.read()如果不是 input_format.is_binary() 和 self.from_encoding:数据 = force_text(数据,self.from_encoding)数据集 = input_format.create_dataset(data)结果 = resource.import_data(数据集,dry_run=False,raise_errors=True)# 将导入的对象添加到 LogEntry加法 = 1改变 = 2删除 = 3logentry_map = {RowResult.IMPORT_TYPE_NEW:添加,RowResult.IMPORT_TYPE_UPDATE:改变,RowResult.IMPORT_TYPE_DELETE:删除,}content_type_id=ContentType.objects.get_for_model(self.model).pk'''对于结果行:LogEntry.objects.log_action(user_id=request.user.pk,content_type_id=content_type_id,object_id=row.object_id,object_repr=row.object_repr,action_flag=logentry_map[row.import_type],change_message="%s 到 import_export" % row.import_type,)'''success_message = _('导入完成')消息.success(self.request,success_message)import_file.close()url = reverse('%s_list' % (str(opts.app_label).lower()))返回 HttpResponseRedirect(url)
模板 import.html 有以下代码:
{% trans "Importar" %} {{ opts.app_label }}
{% if confirm_form %}<form action="{% url "process_import" %}" method="POST">{% csrf_token %}{{confirm_form.as_p }}<p>{% trans "下面是要导入的数据预览.如果对结果满意,请点击'确认导入'" %}</p><div class="submit-row"><input type="submit" class="btn" name="confirm" value="{% trans "Confirm import" %}">
</表单>{% 别的 %}<form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form" enctype="multipart/form-data">{% csrf_token %}<p>{% trans "此导入程序将导入以下字段:" %}{% for f 在字段 %}{% if forloop.counter0 %},{% 万一 %}<tt>{{ f }}</tt>{% 结束为 %}</p><fieldset class="模块对齐">{% 用于表单 %} 中的字段<div class="form-row">{{ field.errors }}{{ field.label_tag }}{{ 场地 }}{% if field.field.help_text %}<p class="help">{{ field.field.help_text|safe }}</p>{% 万一 %}
{% 结束为 %}</fieldset><div class="submit-row"><input type="submit" class="btn" value="{% trans "Submit" %}">
</表单>{% 万一 %}{% 如果结果 %}{% 如果 result.has_errors %}<h2>{% trans "Errors" %}</h2><ul>{% for error in result.base_errors %}<li>{{ error.error }}</li>{% 结束为 %}{% 为行,result.row_errors 中的错误%}{% for error in error %}<li>{% trans "行号" %}: {{ line }} - {{ error.error }}<div class="traceback">{{ error.traceback|linebreaks }}</div>{% 结束为 %}{% 结束为 %}{% 别的 %}<h2>{% trans "预览" %}<表格><头><tr><th></th>{% 用于字段中的字段 %}<th>{{字段}}</th>{% 结束为 %}</tr></thead>{% for row in result.rows %}<tr><td>{% if row.import_type == 'new' %}{% trans "New" %}{% elif row.import_type == '跳过' %}{% trans "Skipped" %}{% elif row.import_type == '删除' %}{% trans "删除" %}{% elif row.import_type == '更新' %}{% trans "更新" %}{% 万一 %}</td>{% 用于 row.diff 中的字段 %}<td>{{ 场地 }}</td>{% 结束为 %}</tr>{% 结束为 %}{% 万一 %}{% 万一 %}
并且 urls.py 应该包含:
#exporturl(r'export/$', login_required(CountryExport.as_view()), name='country_export'),#进口url(r'import/$', login_required(CountryImport.as_view()), name='country_import'),url(r'process_import/$', login_required(CountryProcessImport.as_view()), name='process_import'),
I want to use django-import-export
with class based views.
In the docs at https://django-import-export.readthedocs.org/en/latest/getting_started.html I see an example of exporting as csv
>>> dataset = BookResource().export()
>>> print dataset.csv
id,name,author,author_email,imported,published,price,categories
2,Some book,1,,0,2012-12-05,8.85,1
but which class based view should I use if I want to return an Excel file? Just View
?
解决方案
Jamgreen,
Based on implementation at https://github.com/bmihelac/django-import-export and considering a model "Country" as example with name and abreviation atributes:
First, define at the end of Country models file the Resource:
class CountryResource(resources.ModelResource):
class Meta:
model = Country
Then, implement the class based views:
class CountryExport(View):
def get(self, *args, **kwargs ):
dataset = CountryResource().export()
response = HttpResponse(dataset.csv, content_type="csv")
response['Content-Disposition'] = 'attachment; filename=filename.csv'
return response
class CountryImport(View):
model = Country
from_encoding = "utf-8"
#: import / export formats
DEFAULT_FORMATS = (
base_formats.CSV,
base_formats.XLS,
base_formats.TSV,
base_formats.ODS,
base_formats.JSON,
base_formats.YAML,
base_formats.HTML,
)
formats = DEFAULT_FORMATS
#: template for import view
import_template_name = 'Country/import.html'
resource_class = None
def get_import_formats(self):
"""
Returns available import formats.
"""
return [f for f in self.formats if f().can_import()]
def get_resource_class(self):
if not self.resource_class:
return modelresource_factory(self.model)
else:
return self.resource_class
def get_import_resource_class(self):
"""
Returns ResourceClass to use for import.
"""
return self.get_resource_class()
def get(self, *args, **kwargs ):
'''
Perform a dry_run of the import to make sure the import will not
result in errors. If there where no error, save the user
uploaded file to a local temp file that will be used by
'process_import' for the actual import.
'''
resource = self.get_import_resource_class()()
context = {}
import_formats = self.get_import_formats()
form = ImportForm(import_formats,
self.request.POST or None,
self.request.FILES or None)
if self.request.POST and form.is_valid():
input_format = import_formats[
int(form.cleaned_data['input_format'])
]()
import_file = form.cleaned_data['import_file']
# first always write the uploaded file to disk as it may be a
# memory file or else based on settings upload handlers
with tempfile.NamedTemporaryFile(delete=False) as uploaded_file:
for chunk in import_file.chunks():
uploaded_file.write(chunk)
# then read the file, using the proper format-specific mode
with open(uploaded_file.name,
input_format.get_read_mode()) as uploaded_import_file:
# warning, big files may exceed memory
data = uploaded_import_file.read()
if not input_format.is_binary() and self.from_encoding:
data = force_text(data, self.from_encoding)
dataset = input_format.create_dataset(data)
result = resource.import_data(dataset, dry_run=True,
raise_errors=False)
context['result'] = result
if not result.has_errors():
context['confirm_form'] = ConfirmImportForm(initial={
'import_file_name': os.path.basename(uploaded_file.name),
'input_format': form.cleaned_data['input_format'],
})
context['form'] = form
context['opts'] = self.model._meta
context['fields'] = [f.column_name for f in resource.get_fields()]
return TemplateResponse(self.request, [self.import_template_name], context)
def post(self, *args, **kwargs ):
'''
Perform a dry_run of the import to make sure the import will not
result in errors. If there where no error, save the user
uploaded file to a local temp file that will be used by
'process_import' for the actual import.
'''
resource = self.get_import_resource_class()()
context = {}
import_formats = self.get_import_formats()
form = ImportForm(import_formats,
self.request.POST or None,
self.request.FILES or None)
if self.request.POST and form.is_valid():
input_format = import_formats[
int(form.cleaned_data['input_format'])
]()
import_file = form.cleaned_data['import_file']
# first always write the uploaded file to disk as it may be a
# memory file or else based on settings upload handlers
with tempfile.NamedTemporaryFile(delete=False) as uploaded_file:
for chunk in import_file.chunks():
uploaded_file.write(chunk)
# then read the file, using the proper format-specific mode
with open(uploaded_file.name,
input_format.get_read_mode()) as uploaded_import_file:
# warning, big files may exceed memory
data = uploaded_import_file.read()
if not input_format.is_binary() and self.from_encoding:
data = force_text(data, self.from_encoding)
dataset = input_format.create_dataset(data)
result = resource.import_data(dataset, dry_run=True,
raise_errors=False)
context['result'] = result
if not result.has_errors():
context['confirm_form'] = ConfirmImportForm(initial={
'import_file_name': os.path.basename(uploaded_file.name),
'input_format': form.cleaned_data['input_format'],
})
context['form'] = form
context['opts'] = self.model._meta
context['fields'] = [f.column_name for f in resource.get_fields()]
return TemplateResponse(self.request, [self.import_template_name], context)
class CountryProcessImport(View):
model = Country
from_encoding = "utf-8"
#: import / export formats
DEFAULT_FORMATS = (
base_formats.CSV,
base_formats.XLS,
base_formats.TSV,
base_formats.ODS,
base_formats.JSON,
base_formats.YAML,
base_formats.HTML,
)
formats = DEFAULT_FORMATS
#: template for import view
import_template_name = 'Country/import.html'
resource_class = None
def get_import_formats(self):
"""
Returns available import formats.
"""
return [f for f in self.formats if f().can_import()]
def get_resource_class(self):
if not self.resource_class:
return modelresource_factory(self.model)
else:
return self.resource_class
def get_import_resource_class(self):
"""
Returns ResourceClass to use for import.
"""
return self.get_resource_class()
def post(self, *args, **kwargs ):
'''
Perform the actual import action (after the user has confirmed he
wishes to import)
'''
opts = self.model._meta
resource = self.get_import_resource_class()()
confirm_form = ConfirmImportForm(self.request.POST)
if confirm_form.is_valid():
import_formats = self.get_import_formats()
input_format = import_formats[
int(confirm_form.cleaned_data['input_format'])
]()
import_file_name = os.path.join(
tempfile.gettempdir(),
confirm_form.cleaned_data['import_file_name']
)
import_file = open(import_file_name, input_format.get_read_mode())
data = import_file.read()
if not input_format.is_binary() and self.from_encoding:
data = force_text(data, self.from_encoding)
dataset = input_format.create_dataset(data)
result = resource.import_data(dataset, dry_run=False,
raise_errors=True)
# Add imported objects to LogEntry
ADDITION = 1
CHANGE = 2
DELETION = 3
logentry_map = {
RowResult.IMPORT_TYPE_NEW: ADDITION,
RowResult.IMPORT_TYPE_UPDATE: CHANGE,
RowResult.IMPORT_TYPE_DELETE: DELETION,
}
content_type_id=ContentType.objects.get_for_model(self.model).pk
'''
for row in result:
LogEntry.objects.log_action(
user_id=request.user.pk,
content_type_id=content_type_id,
object_id=row.object_id,
object_repr=row.object_repr,
action_flag=logentry_map[row.import_type],
change_message="%s through import_export" % row.import_type,
)
'''
success_message = _('Import finished')
messages.success(self.request, success_message)
import_file.close()
url = reverse('%s_list' % (str(opts.app_label).lower()))
return HttpResponseRedirect(url)
the template import.html has the following code:
<h1>{% trans "Importar" %} {{ opts.app_label }}</h1>
{% if confirm_form %}
<form action="{% url "process_import" %}" method="POST">
{% csrf_token %}
{{ confirm_form.as_p }}
<p>
{% trans "Below is a preview of data to be imported. If you are satisfied with the results, click 'Confirm import'" %}
</p>
<div class="submit-row">
<input type="submit" class="btn" name="confirm" value="{% trans "Confirm import" %}">
</div>
</form>
{% else %}
<form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form" enctype="multipart/form-data">
{% csrf_token %}
<p>
{% trans "This importer will import the following fields: " %}
{% for f in fields %}
{% if forloop.counter0 %}
,
{% endif %}
<tt>{{ f }}</tt>
{% endfor %}
</p>
<fieldset class="module aligned">
{% for field in form %}
<div class="form-row">
{{ field.errors }}
{{ field.label_tag }}
{{ field }}
{% if field.field.help_text %}
<p class="help">{{ field.field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
</fieldset>
<div class="submit-row">
<input type="submit" class="btn" value="{% trans "Submit" %}">
</div>
</form>
{% endif %}
{% if result %}
{% if result.has_errors %}
<h2>{% trans "Errors" %}</h2>
<ul>
{% for error in result.base_errors %}
<li>{{ error.error }}</li>
{% endfor %}
{% for line, errors in result.row_errors %}
{% for error in errors %}
<li>
{% trans "Line number" %}: {{ line }} - {{ error.error }}
<div class="traceback">{{ error.traceback|linebreaks }}</div>
</li>
{% endfor %}
{% endfor %}
</ul>
{% else %}
<h2>
{% trans "Preview" %}
</h2>
<table>
<thead>
<tr>
<th></th>
{% for field in fields %}
<th>{{ field }}</th>
{% endfor %}
</tr>
</thead>
{% for row in result.rows %}
<tr>
<td>
{% if row.import_type == 'new' %}
{% trans "New" %}
{% elif row.import_type == 'skip' %}
{% trans "Skipped" %}
{% elif row.import_type == 'delete' %}
{% trans "Delete" %}
{% elif row.import_type == 'update' %}
{% trans "Update" %}
{% endif %}
</td>
{% for field in row.diff %}
<td>
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
{% endif %}
{% endif %}
and the urls.py should contain:
#export
url(r'export/$', login_required(CountryExport.as_view()), name='country_export'),
#import
url(r'import/$', login_required(CountryImport.as_view()), name='country_import'),
url(r'process_import/$', login_required(CountryProcessImport.as_view()), name='process_import'),
这篇关于将 django-import-export 与基于类的视图一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!