From 6837bc14602849b3543add71ad3f731e38b8fc2d Mon Sep 17 00:00:00 2001 From: Lie Ryan Date: Mon, 12 Nov 2018 18:51:33 +1100 Subject: [PATCH 1/3] Make pandas an optional dependency Importing pandas/numpy can be slow (it doubles the startup time of ./manage.py, and some people reports that pandas takes seconds to load), and it's a pretty huge dependency for a functionality that is already in the standard library. Making it an optional dependency makes it easy for people to gain pandas speedup while not incurring the cost for those who don't need it. --- README.rst | 9 ++++++++- django_csv_exports/admin.py | 15 ++++++++++++--- setup.py | 14 ++++++++------ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index bbc473d..1762757 100644 --- a/README.rst +++ b/README.rst @@ -17,7 +17,7 @@ Installation - Python 2.7, 3.3+ - `Django `_ >= 1.5 -- Pandas +- (optional) Pandas - Numpy - python-dateutil - pytz @@ -26,6 +26,13 @@ To install:: pip install django-csv-exports +or to include the optional dependency:: + + pip install django-csv-exports[pandas] + +Exporting with pandas may be faster than the standard library under certain +circumstances, test with your dataset. + Next add `django_exports` to your `INSTALLED_APPS` to include the related css/js:: INSTALLED_APPS = ( diff --git a/django_csv_exports/admin.py b/django_csv_exports/admin.py index ae8c321..ca1f974 100644 --- a/django_csv_exports/admin.py +++ b/django_csv_exports/admin.py @@ -1,6 +1,9 @@ import csv -import pandas +try: + import pandas +except ImportError: + pandas = None import django from django.conf import settings @@ -37,8 +40,14 @@ def export_as_csv(admin_model, request, queryset): response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename=%s.csv' % text(opts).replace('.', '_') - queryset = queryset.values_list(*field_names) - pandas.DataFrame(list(queryset), columns=field_names).to_csv(response, index=False, encoding='utf-8') + if pandas is not None: + queryset = queryset.values_list(*field_names) + pandas.DataFrame(list(queryset), columns=field_names).to_csv(response, index=False, encoding='utf-8') + else: + writer = csv.writer(response) + writer.writerow(list(field_names)) + for obj in queryset: + writer.writerow([text(getattr(obj, field)).encode("utf-8", "replace") for field in field_names]) return response return HttpResponseForbidden() export_as_csv.short_description = "Export selected objects as csv file" diff --git a/setup.py b/setup.py index e6124e8..9f5694d 100644 --- a/setup.py +++ b/setup.py @@ -35,10 +35,12 @@ def read_file(filename): long_description=read_file('README.rst'), test_suite="runtests.runtests", zip_safe=False, - install_requires=[ - 'pandas', - 'numpy', - 'python-dateutil', - 'pytz' - ] + extras_require={ + 'pandas': [ + 'pandas', + 'numpy', + 'python-dateutil', + 'pytz' + ] + } ) From c55d5fc5879584cbecdb0c45d3f434817eb1a9be Mon Sep 17 00:00:00 2001 From: Lie Ryan Date: Mon, 12 Nov 2018 19:01:12 +1100 Subject: [PATCH 2/3] Import pandas lazily --- django_csv_exports/admin.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/django_csv_exports/admin.py b/django_csv_exports/admin.py index ca1f974..8843814 100644 --- a/django_csv_exports/admin.py +++ b/django_csv_exports/admin.py @@ -1,10 +1,5 @@ import csv -try: - import pandas -except ImportError: - pandas = None - import django from django.conf import settings from django.contrib import admin @@ -17,6 +12,13 @@ def export_as_csv(admin_model, request, queryset): Generic csv export admin action. based on http://djangosnippets.org/snippets/1697/ """ + + # import pandas lazily as to not slow down ./manage.py + try: + import pandas + except ImportError: + pandas = None + # everyone has perms to export as csv unless explicitly defined if getattr(settings, 'DJANGO_EXPORTS_REQUIRE_PERM', None): admin_opts = admin_model.opts From 52994129a887831a601d34027f1df717bd290985 Mon Sep 17 00:00:00 2001 From: Lie Ryan Date: Mon, 12 Nov 2018 20:12:31 +1100 Subject: [PATCH 3/3] Fix rendering of bytes to match pandas rendering This assumes Python 3, but the code is already broken on Python 2 anyway. --- django_csv_exports/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_csv_exports/admin.py b/django_csv_exports/admin.py index 8843814..6f843fe 100644 --- a/django_csv_exports/admin.py +++ b/django_csv_exports/admin.py @@ -49,7 +49,7 @@ def export_as_csv(admin_model, request, queryset): writer = csv.writer(response) writer.writerow(list(field_names)) for obj in queryset: - writer.writerow([text(getattr(obj, field)).encode("utf-8", "replace") for field in field_names]) + writer.writerow([text(getattr(obj, field)) for field in field_names]) return response return HttpResponseForbidden() export_as_csv.short_description = "Export selected objects as csv file"