forked from django-import-export/django-import-export
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadmin.py
223 lines (183 loc) · 7.59 KB
/
admin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import tempfile
from datetime import datetime
import tablib
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from django.conf.urls.defaults import patterns, url
from django.template.response import TemplateResponse
from django.contrib import messages
from django.http import HttpResponseRedirect, HttpResponse
from django.utils.importlib import import_module
from django.core.urlresolvers import reverse
from .forms import (
ImportForm,
ConfirmImportForm,
)
from .resources import (
modelresource_factory,
)
class ImportMixin(object):
change_list_template = 'admin/import_export/change_list_import.html'
import_template_name = 'admin/import_export/import.html'
resource_class = None
format_choices = (
('', '---'),
('tablib.formats._csv', 'CSV'),
('tablib.formats._xls', 'Excel XLS'),
)
from_encoding = "utf-8"
def get_urls(self):
urls = super(ImportMixin, self).get_urls()
info = self.model._meta.app_label, self.model._meta.module_name
my_urls = patterns('',
url(r'^process_import/$',
self.admin_site.admin_view(self.process_import),
name='%s_%s_process_import' % info),
url(r'^import/$',
self.admin_site.admin_view(self.import_action),
name='%s_%s_import' % info),
)
return my_urls + urls
def get_resource_class(self):
if not self.resource_class:
return modelresource_factory(self.model)
else:
return self.resource_class
def get_format(self, format_class):
if format_class:
return import_module(format_class)
return None
def get_mode_for_format(self, format):
"""
Returns mode for opening files.
"""
return 'rU'
def load_dataset(self, stream, input_format=None, from_encoding=None):
"""
Loads data from ``stream`` given valid tablib ``input_format``
and returns tablib dataset
If ``from_encoding`` is specified, data will be converted to `utf-8`
characterset.
"""
if from_encoding:
text = unicode(stream.read(), from_encoding).encode('utf-8')
else:
text = stream.read()
if not input_format:
data = tablib.import_set(text)
else:
data = tablib.Dataset()
input_format.import_set(data, text)
return data
def process_import(self, request, *args, **kwargs):
opts = self.model._meta
resource = self.get_resource_class()()
confirm_form = ConfirmImportForm(request.POST)
if confirm_form.is_valid():
input_format = self.get_format(
confirm_form.cleaned_data['input_format'])
import_mode = self.get_mode_for_format(input_format)
import_file = open(confirm_form.cleaned_data['import_file_name'],
import_mode)
dataset = self.load_dataset(import_file, input_format,
self.from_encoding)
resource.import_data(dataset, dry_run=False,
raise_errors=True)
success_message = _('Import finished')
messages.success(request, success_message)
import_file.close()
url = reverse('admin:%s_%s_changelist' %
(opts.app_label, opts.module_name),
current_app=self.admin_site.name)
return HttpResponseRedirect(url)
def import_action(self, request, *args, **kwargs):
resource = self.get_resource_class()()
context = {}
form = ImportForm(self.format_choices,
request.POST or None,
request.FILES or None)
if request.POST:
if form.is_valid():
input_format = self.get_format(
form.cleaned_data['input_format'])
import_mode = self.get_mode_for_format(input_format)
import_file = form.cleaned_data['import_file']
import_file.open(import_mode)
dataset = self.load_dataset(import_file, input_format,
self.from_encoding)
result = resource.import_data(dataset, dry_run=True,
raise_errors=False)
context['result'] = result
if not result.has_errors():
tmp_file = tempfile.NamedTemporaryFile(delete=False)
for chunk in import_file.chunks():
tmp_file.write(chunk)
tmp_file.close()
context['confirm_form'] = ConfirmImportForm(initial={
'import_file_name': tmp_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(request, [self.import_template_name],
context, current_app=self.admin_site.name)
class ExportMixin(object):
resource_class = None
change_list_template = 'admin/import_export/change_list_export.html'
export_format = 'csv'
to_encoding = "utf-8"
def get_urls(self):
urls = super(ExportMixin, self).get_urls()
info = self.model._meta.app_label, self.model._meta.module_name
my_urls = patterns('',
url(r'^export/$',
self.admin_site.admin_view(self.export_action),
name='%s_%s_export' % info),
)
return my_urls + urls
def get_resource_class(self):
if not self.resource_class:
return modelresource_factory(self.model)
else:
return self.resource_class
def get_export_filename(self):
date_str = datetime.now().strftime('%Y-%m-%d')
filename = "%s-%s.%s" % (self.model.__name__,
date_str, self.export_format)
return filename
def get_export_queryset(self, request):
"""
Returns export queryset.
Default implementation respects applied search and filters.
"""
# copied from django/contrib/admin/options.py
list_display = self.get_list_display(request)
list_display_links = self.get_list_display_links(request, list_display)
ChangeList = self.get_changelist(request)
cl = ChangeList(request, self.model, list_display,
list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related,
self.list_per_page, self.list_max_show_all, self.list_editable,
self)
return cl.query_set
def export_action(self, request, *args, **kwargs):
resource_class = self.get_resource_class()
queryset = self.get_export_queryset(request)
data = resource_class().export(queryset)
filename = self.get_export_filename()
response = HttpResponse(
getattr(data, self.export_format),
mimetype='application/octet-stream',
)
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
class ImportExportMixin(ImportMixin, ExportMixin):
"""
Import and export mixin.
"""
change_list_template = 'admin/import_export/change_list_import_export.html'
class ImportExportModelAdmin(ImportExportMixin, admin.ModelAdmin):
"""
Subclass of ModelAdmin with import/export functionality.
"""