Skip to content

Instantly share code, notes, and snippets.

@int-ua
Created December 28, 2017 19:38
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save int-ua/b2bcc4bea8227ab14a437900ff424723 to your computer and use it in GitHub Desktop.
Save int-ua/b2bcc4bea8227ab14a437900ff424723 to your computer and use it in GitHub Desktop.
Import management command for django-import-export
# https://gist.github.com/bmihelac/434fceb6ba8e752f08d3
# https://github.com/django-import-export/django-import-export/issues/332
from __future__ import unicode_literals
import mimetypes
from django.core.management.base import BaseCommand, CommandError
from django.utils import termcolors
from django.utils.encoding import force_text
from import_export.formats import base_formats
FORMATS = {
None: base_formats.CSV,
'text/csv': base_formats.CSV,
'application/vnd.ms-excel': base_formats.XLS,
}
style_ok = termcolors.make_style(opts=('bold',), fg='green')
class Command(BaseCommand):
'''
./manage import_file filename.csv\
--resource_class apps..admin.Resource\
--model_name apps..models.\
--raise-errors
'''
args = '<import_file_name>'
def add_arguments(self, parser):
parser.add_argument(
'--resource_class',
dest='resource_class',
default=None,
help='Resource class as dotted path,'
'ie: mymodule.resources.MyResource'),
parser.add_argument(
'--model_name',
dest='model_name',
default=None,
help='Model name, ie: auth.User'),
parser.add_argument(
'--dry-run',
action='store_true',
dest='dry_run',
default=False,
help='Dry run'),
parser.add_argument(
'--raise-errors',
action='store_true',
dest='raise_errors',
help='Raise errors'),
parser.add_argument(
'--no-raise-errors',
action='store_false',
dest='raise_errors',
help='Do not raise errors')
def get_resource_class(self, resource_class, model_name):
from django.utils.module_loading import import_by_path
from django.db import models
from import_export.resources import modelresource_factory
if not resource_class:
return modelresource_factory(models.get_model(model_name))
else:
return import_by_path(resource_class)
def handle(self, *args, **options):
dry_run = options.get('dry_run')
if dry_run:
self.stdout.write(self.style.NOTICE('Dry run'))
raise_errors = options.get('raise_errors', None)
if raise_errors is None:
raise_errors = not dry_run
import_file_name = args[0]
mimetype = mimetypes.guess_type(import_file_name)[0]
input_format = FORMATS[mimetype]()
resource_class = self.get_resource_class(
options.get('resource_class'),
options.get('model_name')
)
resource = resource_class()
read_mode = input_format.get_read_mode()
try:
with open(import_file_name, read_mode) as import_file:
data = import_file.read()
except (OSError, FileNotFoundError) as e:
raise CommandError(str(e))
dataset = input_format.create_dataset(data)
result = resource.import_data(
dataset,
dry_run=dry_run,
raise_errors=raise_errors
)
if result.has_errors():
self.stdout.write(self.style.ERROR('Errors'))
for error in result.base_errors:
self.stdout.write(error.error, self.style.ERROR)
for line, errors in result.row_errors():
for error in errors:
self.stdout.write(self.style.ERROR(
'Line number' + ': ' + force_text(line) + ' - ' +
force_text(error.error)))
else:
self.stdout.write(style_ok('OK'))
@callumgare
Copy link

Thanks very much for this! I've updated it to work for Django 3.2 (and possibly newer but have only tested 3.2): https://gist.github.com/callumgare/e1a8f4145457bd1458de6276887ae3a5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment