def load_from_file(request, book_slug): book = get_object_or_404(Book, slug=book_slug, users=request.user) if request.method == 'POST': form = CSVExpenseForm(book=book, data=request.POST, files=request.FILES) if form.is_valid(): csv_file = form.cleaned_data.get('csv_file') if csv_file: # Hack around: "iterator should return strings, not bytes # (did you open the file in text mode?)" csv_file.readable = lambda: True csv_file.writable = lambda: False csv_file = TextIOWrapper(csv_file, encoding='utf-8') # end hack else: csv_content = form.cleaned_data.get('csv_content') csv_file = StringIO(csv_content) csv_file.name = '' account = form.cleaned_data['account'] if account.parser_config is None: messages.error( request, 'Parser config for account %s is not set.' % account, ) return HttpResponseRedirect('.') result = CSVParser(account).parse(csv_file, book=book, user=request.user) success = len(result['entries']) errors = len(result['errors']) if not errors: messages.success( request, 'File %s successfully parsed (%s entries added).' % (csv_file.name, success), ) elif success: messages.warning( request, 'File %s partially parsed (%s successes, %s errors).' % (csv_file.name, success, errors), ) else: messages.error( request, 'File %s could not be parsed (%s errors).' % (csv_file.name, errors), ) if errors: for error in result['errors']: e = error['exception'] msg = error['message'] data = error['data'] messages.error(request, '%s\n\n%s\n%r' % (e, msg, data)) return HttpResponseRedirect( reverse('entries', kwargs=dict(book_slug=book_slug))) else: form = CSVExpenseForm(book=book) context = dict(form=form) return render(request, 'gemcore/load.html', context)