Add better support for "make import batch from file" pattern
This commit is contained in:
		
							parent
							
								
									0375d66b91
								
							
						
					
					
						commit
						4fa9ab3c6e
					
				
					 6 changed files with 80 additions and 6 deletions
				
			
		|  | @ -2,7 +2,7 @@ | ||||||
| ################################################################################ | ################################################################################ | ||||||
| # | # | ||||||
| #  Rattail -- Retail Software Framework | #  Rattail -- Retail Software Framework | ||||||
| #  Copyright © 2010-2017 Lance Edgar | #  Copyright © 2010-2018 Lance Edgar | ||||||
| # | # | ||||||
| #  This file is part of Rattail. | #  This file is part of Rattail. | ||||||
| # | # | ||||||
|  | @ -28,4 +28,4 @@ from __future__ import unicode_literals, absolute_import | ||||||
| 
 | 
 | ||||||
| from . import types | from . import types | ||||||
| from . import widgets | from . import widgets | ||||||
| from .core import Form | from .core import Form, SimpleFileImport | ||||||
|  |  | ||||||
|  | @ -881,3 +881,21 @@ class FieldList(list): | ||||||
|     def insert_after(self, field, newfield): |     def insert_after(self, field, newfield): | ||||||
|         i = self.index(field) |         i = self.index(field) | ||||||
|         self.insert(i + 1, newfield) |         self.insert(i + 1, newfield) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @colander.deferred | ||||||
|  | def upload_widget(node, kw): | ||||||
|  |     request = kw['request'] | ||||||
|  |     tmpstore = SessionFileUploadTempStore(request) | ||||||
|  |     return dfwidget.FileUploadWidget(tmpstore) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class SimpleFileImport(colander.Schema): | ||||||
|  |     """ | ||||||
|  |     Schema for simple file import.  Note that you must bind your ``request`` | ||||||
|  |     object to this schema, i.e.:: | ||||||
|  | 
 | ||||||
|  |        schema = SimpleFileImport().bind(request=request) | ||||||
|  |     """ | ||||||
|  |     filename = colander.SchemaNode(deform.FileData(), | ||||||
|  |                                    widget=upload_widget) | ||||||
|  |  | ||||||
|  | @ -79,7 +79,7 @@ | ||||||
|   ${self.context_menu_items()} |   ${self.context_menu_items()} | ||||||
| </ul> | </ul> | ||||||
| 
 | 
 | ||||||
| % if status_breakdown is not Undefined: | % if status_breakdown is not Undefined and status_breakdown is not None: | ||||||
|     <div class="object-helper"> |     <div class="object-helper"> | ||||||
|       <h3>Row Status Breakdown</h3> |       <h3>Row Status Breakdown</h3> | ||||||
|       <div class="object-helper-content"> |       <div class="object-helper-content"> | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								tailbone/templates/master/import_file.mako
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tailbone/templates/master/import_file.mako
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | ## -*- coding: utf-8; -*- | ||||||
|  | <%inherit file="/master/create.mako" /> | ||||||
|  | 
 | ||||||
|  | <%def name="title()">Import ${model_title_plural} from ${importer_host_title}</%def> | ||||||
|  | 
 | ||||||
|  | ${parent.body()} | ||||||
|  | @ -103,15 +103,23 @@ class ImporterBatchView(BatchMasterView): | ||||||
|         f.set_readonly('importer_key') |         f.set_readonly('importer_key') | ||||||
|         f.set_readonly('row_table') |         f.set_readonly('row_table') | ||||||
| 
 | 
 | ||||||
|  |     def make_status_breakdown(self, batch): | ||||||
|  |         # TODO: should implement this, just can't use batch.data_rows apparently | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|     def delete_instance(self, batch): |     def delete_instance(self, batch): | ||||||
|         self.make_row_table(batch.row_table) |         self.make_row_table(batch.row_table) | ||||||
|  |         if self.current_row_table is not None: | ||||||
|             self.current_row_table.drop() |             self.current_row_table.drop() | ||||||
|         super(ImporterBatchView, self).delete_instance(batch) |         super(ImporterBatchView, self).delete_instance(batch) | ||||||
| 
 | 
 | ||||||
|     def make_row_table(self, name): |     def make_row_table(self, name): | ||||||
|         if not hasattr(self, 'current_row_table'): |         if not hasattr(self, 'current_row_table'): | ||||||
|             metadata = sa.MetaData(schema='batch', bind=self.Session.bind) |             metadata = sa.MetaData(schema='batch', bind=self.Session.bind) | ||||||
|  |             try: | ||||||
|                 self.current_row_table = sa.Table(name, metadata, autoload=True) |                 self.current_row_table = sa.Table(name, metadata, autoload=True) | ||||||
|  |             except sa.exc.NoSuchTableError: | ||||||
|  |                 self.current_row_table = None | ||||||
| 
 | 
 | ||||||
|     def get_row_data(self, batch): |     def get_row_data(self, batch): | ||||||
|         self.make_row_table(batch.row_table) |         self.make_row_table(batch.row_table) | ||||||
|  |  | ||||||
|  | @ -89,6 +89,7 @@ class MasterView(View): | ||||||
|     execute_progress_template = None |     execute_progress_template = None | ||||||
|     execute_progress_initial_msg = None |     execute_progress_initial_msg = None | ||||||
|     supports_prev_next = False |     supports_prev_next = False | ||||||
|  |     supports_import_batch_from_file = False | ||||||
| 
 | 
 | ||||||
|     supports_mobile = False |     supports_mobile = False | ||||||
|     mobile_creatable = False |     mobile_creatable = False | ||||||
|  | @ -705,6 +706,10 @@ class MasterView(View): | ||||||
|             if isinstance(node.typ, deform.FileData): |             if isinstance(node.typ, deform.FileData): | ||||||
|                 if skip and node.name in skip: |                 if skip and node.name in skip: | ||||||
|                     continue |                     continue | ||||||
|  |                 # TODO: does form ever *not* have 'validated' attr here? | ||||||
|  |                 if hasattr(form, 'validated'): | ||||||
|  |                     filedict = form.validated.get(node.name) | ||||||
|  |                 else: | ||||||
|                     filedict = self.form_deserialized.get(node.name) |                     filedict = self.form_deserialized.get(node.name) | ||||||
|                 if filedict: |                 if filedict: | ||||||
|                     tempdir = tempfile.mkdtemp() |                     tempdir = tempfile.mkdtemp() | ||||||
|  | @ -722,6 +727,38 @@ class MasterView(View): | ||||||
|     def process_uploads(self, obj, form, uploads): |     def process_uploads(self, obj, form, uploads): | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|  |     def import_batch_from_file(self, handler_factory, model_name, | ||||||
|  |                                delete=False, schema=None, importer_host_title=None): | ||||||
|  | 
 | ||||||
|  |         handler = handler_factory(self.rattail_config) | ||||||
|  | 
 | ||||||
|  |         if not schema: | ||||||
|  |             schema = forms.SimpleFileImport().bind(request=self.request) | ||||||
|  |         form = forms.Form(schema=schema, request=self.request) | ||||||
|  |         form.save_label = "Upload" | ||||||
|  |         form.cancel_url = self.get_index_url() | ||||||
|  |         if form.validate(newstyle=True): | ||||||
|  | 
 | ||||||
|  |             uploads = self.normalize_uploads(form) | ||||||
|  |             filepath = uploads['filename']['temp_path'] | ||||||
|  |             batches = handler.make_batches(model_name, | ||||||
|  |                                            delete=delete, | ||||||
|  |                                            # tdc_input_path=filepath, | ||||||
|  |                                            # source_csv_path=filepath, | ||||||
|  |                                            source_data_path=filepath, | ||||||
|  |                                            runas_user=self.request.user) | ||||||
|  |             batch = batches[0] | ||||||
|  |             return self.redirect(self.request.route_url('batch.importer.view', uuid=batch.uuid)) | ||||||
|  | 
 | ||||||
|  |         if not importer_host_title: | ||||||
|  |             importer_host_title = handler.host_title | ||||||
|  | 
 | ||||||
|  |         return self.render_to_response('import_file', { | ||||||
|  |             'form': form, | ||||||
|  |             'dform': form.make_deform_form(), | ||||||
|  |             'importer_host_title': importer_host_title, | ||||||
|  |         }) | ||||||
|  | 
 | ||||||
|     def render_product_key_value(self, obj): |     def render_product_key_value(self, obj): | ||||||
|         """ |         """ | ||||||
|         Render the "canonical" product key value for the given object. |         Render the "canonical" product key value for the given object. | ||||||
|  | @ -3087,6 +3124,11 @@ class MasterView(View): | ||||||
|             config.add_tailbone_permission(permission_prefix, '{0}.delete'.format(permission_prefix), |             config.add_tailbone_permission(permission_prefix, '{0}.delete'.format(permission_prefix), | ||||||
|                                            "Delete {0}".format(model_title)) |                                            "Delete {0}".format(model_title)) | ||||||
| 
 | 
 | ||||||
|  |         # import batch from file | ||||||
|  |         if cls.supports_import_batch_from_file: | ||||||
|  |             config.add_tailbone_permission(permission_prefix, '{}.import_file'.format(permission_prefix), | ||||||
|  |                                            "Create a new import batch from data file") | ||||||
|  | 
 | ||||||
|         ### sub-rows stuff follows |         ### sub-rows stuff follows | ||||||
| 
 | 
 | ||||||
|         # download row results as CSV |         # download row results as CSV | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar