1
1
import tempfile
2
2
from datetime import datetime
3
3
4
- import tablib
5
-
6
4
from django .contrib import admin
7
5
from django .utils .translation import ugettext_lazy as _
8
6
from django .conf .urls .defaults import patterns , url
9
7
from django .template .response import TemplateResponse
10
8
from django .contrib import messages
11
9
from django .http import HttpResponseRedirect , HttpResponse
12
- from django .utils .importlib import import_module
13
10
from django .core .urlresolvers import reverse
14
11
15
12
from .forms import (
16
13
ImportForm ,
17
14
ConfirmImportForm ,
15
+ ExportForm ,
18
16
)
19
17
from .resources import (
20
18
modelresource_factory ,
21
19
)
20
+ from .formats import base_formats
21
+
22
+
23
+ DEFAULT_FORMATS = (
24
+ base_formats .CSV ,
25
+ base_formats .XLS ,
26
+ base_formats .TSV ,
27
+ base_formats .ODS ,
28
+ base_formats .JSON ,
29
+ base_formats .YAML ,
30
+ base_formats .HTML ,
31
+ )
22
32
23
33
24
34
class ImportMixin (object ):
@@ -29,10 +39,7 @@ class ImportMixin(object):
29
39
change_list_template = 'admin/import_export/change_list_import.html'
30
40
import_template_name = 'admin/import_export/import.html'
31
41
resource_class = None
32
- format_choices = (
33
- ('' , '---' ),
34
- ('tablib.formats._csv' , 'CSV' ),
35
- )
42
+ formats = DEFAULT_FORMATS
36
43
from_encoding = "utf-8"
37
44
38
45
def get_urls (self ):
@@ -54,50 +61,29 @@ def get_resource_class(self):
54
61
else :
55
62
return self .resource_class
56
63
57
- def get_format (self , format_class ):
58
- if format_class :
59
- return import_module (format_class )
60
- return None
61
-
62
- def get_mode_for_format (self , format ):
63
- """
64
- Returns mode for opening files.
64
+ def get_import_formats (self ):
65
65
"""
66
- return 'rU'
67
-
68
- def load_dataset (self , stream , input_format = None , from_encoding = None ):
69
- """
70
- Loads data from ``stream`` given valid tablib ``input_format``
71
- and returns tablib dataset
72
-
73
- If ``from_encoding`` is specified, data will be converted to `utf-8`
74
- characterset.
66
+ Returns available import formats.
75
67
"""
76
- if from_encoding :
77
- text = unicode (stream .read (), from_encoding ).encode ('utf-8' )
78
- else :
79
- text = stream .read ()
80
- if not input_format :
81
- data = tablib .import_set (text )
82
- else :
83
- data = tablib .Dataset ()
84
- input_format .import_set (data , text )
85
- return data
68
+ return [f for f in self .formats if f ().can_import ()]
86
69
87
70
def process_import (self , request , * args , ** kwargs ):
88
71
opts = self .model ._meta
89
72
resource = self .get_resource_class ()()
90
73
91
74
confirm_form = ConfirmImportForm (request .POST )
92
75
if confirm_form .is_valid ():
93
- input_format = self .get_format (
94
- confirm_form .cleaned_data ['input_format' ])
95
- import_mode = self .get_mode_for_format (input_format )
76
+ import_formats = self .get_import_formats ()
77
+ input_format = import_formats [
78
+ int (confirm_form .cleaned_data ['input_format' ])
79
+ ]()
96
80
import_file = open (confirm_form .cleaned_data ['import_file_name' ],
97
- import_mode )
81
+ input_format .get_read_mode ())
82
+ data = import_file .read ()
83
+ if not input_format .is_binary () and self .from_encoding :
84
+ data = unicode (data , self .from_encoding ).encode ('utf-8' )
85
+ dataset = input_format .create_dataset (data )
98
86
99
- dataset = self .load_dataset (import_file , input_format ,
100
- self .from_encoding )
101
87
resource .import_data (dataset , dry_run = False ,
102
88
raise_errors = True )
103
89
@@ -115,34 +101,34 @@ def import_action(self, request, *args, **kwargs):
115
101
116
102
context = {}
117
103
118
- form = ImportForm (self .format_choices ,
104
+ import_formats = self .get_import_formats ()
105
+ form = ImportForm (import_formats ,
119
106
request .POST or None ,
120
107
request .FILES or None )
121
108
122
- if request .POST :
123
- if form .is_valid ():
124
- input_format = self .get_format (
125
- form .cleaned_data ['input_format' ])
126
- import_mode = self .get_mode_for_format (input_format )
127
- import_file = form .cleaned_data ['import_file' ]
128
- import_file .open (import_mode )
129
-
130
- dataset = self .load_dataset (import_file , input_format ,
131
- self .from_encoding )
132
- result = resource .import_data (dataset , dry_run = True ,
133
- raise_errors = False )
134
-
135
- context ['result' ] = result
136
-
137
- if not result .has_errors ():
138
- tmp_file = tempfile .NamedTemporaryFile (delete = False )
139
- for chunk in import_file .chunks ():
140
- tmp_file .write (chunk )
141
- tmp_file .close ()
142
- context ['confirm_form' ] = ConfirmImportForm (initial = {
143
- 'import_file_name' : tmp_file .name ,
144
- 'input_format' : form .cleaned_data ['input_format' ],
145
- })
109
+ if request .POST and form .is_valid ():
110
+ input_format = import_formats [
111
+ int (form .cleaned_data ['input_format' ])
112
+ ]()
113
+ import_file = form .cleaned_data ['import_file' ]
114
+ import_file .open (input_format .get_read_mode ())
115
+ data = import_file .read ()
116
+ if not input_format .is_binary () and self .from_encoding :
117
+ data = unicode (data , self .from_encoding ).encode ('utf-8' )
118
+ dataset = input_format .create_dataset (data )
119
+ result = resource .import_data (dataset , dry_run = True ,
120
+ raise_errors = False )
121
+
122
+ context ['result' ] = result
123
+
124
+ if not result .has_errors ():
125
+ tmp_file = tempfile .NamedTemporaryFile (delete = False )
126
+ tmp_file .write (data )
127
+ tmp_file .close ()
128
+ context ['confirm_form' ] = ConfirmImportForm (initial = {
129
+ 'import_file_name' : tmp_file .name ,
130
+ 'input_format' : form .cleaned_data ['input_format' ],
131
+ })
146
132
147
133
context ['form' ] = form
148
134
context ['opts' ] = self .model ._meta
@@ -158,7 +144,8 @@ class ExportMixin(object):
158
144
"""
159
145
resource_class = None
160
146
change_list_template = 'admin/import_export/change_list_export.html'
161
- export_format = 'csv'
147
+ export_template_name = 'admin/import_export/export.html'
148
+ formats = DEFAULT_FORMATS
162
149
to_encoding = "utf-8"
163
150
164
151
def get_urls (self ):
@@ -177,10 +164,17 @@ def get_resource_class(self):
177
164
else :
178
165
return self .resource_class
179
166
180
- def get_export_filename (self ):
167
+ def get_export_formats (self ):
168
+ """
169
+ Returns available import formats.
170
+ """
171
+ return [f for f in self .formats if f ().can_export ()]
172
+
173
+ def get_export_filename (self , file_format ):
181
174
date_str = datetime .now ().strftime ('%Y-%m-%d' )
182
175
filename = "%s-%s.%s" % (self .model .__name__ ,
183
- date_str , self .export_format )
176
+ date_str ,
177
+ file_format .get_extension ())
184
178
return filename
185
179
186
180
def get_export_queryset (self , request ):
@@ -203,16 +197,30 @@ def get_export_queryset(self, request):
203
197
return cl .query_set
204
198
205
199
def export_action (self , request , * args , ** kwargs ):
206
- resource_class = self .get_resource_class ()
207
- queryset = self .get_export_queryset (request )
208
- data = resource_class ().export (queryset )
209
- filename = self .get_export_filename ()
210
- response = HttpResponse (
211
- getattr (data , self .export_format ),
212
- mimetype = 'application/octet-stream' ,
213
- )
214
- response ['Content-Disposition' ] = 'attachment; filename=%s' % filename
215
- return response
200
+ formats = self .get_export_formats ()
201
+ form = ExportForm (formats , request .POST or None )
202
+ if form .is_valid ():
203
+ file_format = formats [
204
+ int (form .cleaned_data ['file_format' ])
205
+ ]()
206
+
207
+ resource_class = self .get_resource_class ()
208
+ queryset = self .get_export_queryset (request )
209
+ data = resource_class ().export (queryset )
210
+ response = HttpResponse (
211
+ file_format .export_data (data ),
212
+ mimetype = 'application/octet-stream' ,
213
+ )
214
+ response ['Content-Disposition' ] = 'attachment; filename=%s' % (
215
+ self .get_export_filename (file_format ),
216
+ )
217
+ return response
218
+
219
+ context = {}
220
+ context ['form' ] = form
221
+ context ['opts' ] = self .model ._meta
222
+ return TemplateResponse (request , [self .export_template_name ],
223
+ context , current_app = self .admin_site .name )
216
224
217
225
218
226
class ImportExportMixin (ImportMixin , ExportMixin ):
0 commit comments