Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the Django DurationField with DurationWidget. #575

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ local_settings.py
docs/_build
build/
dist/
/django-import-export/
*.egg-info/
.tox/
.idea/
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,4 @@ The following is a list of much appreciated contributors:
* adamcharnock (Adam Charnock)
* paveltyavin (Pavel)
* jameshiew (James Hiew)
* mgrdcm (Dan Moore)
3 changes: 3 additions & 0 deletions docs/api_widgets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ Widgets
.. autoclass:: import_export.widgets.DateTimeWidget
:members:

.. autoclass:: import_export.widgets.DurationWidget
:members:

.. autoclass:: import_export.widgets.ForeignKeyWidget
:members:

Expand Down
2 changes: 2 additions & 0 deletions import_export/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,8 @@ def widget_from_django_field(cls, f, default=widgets.Widget):
result = widgets.DateWidget
elif internal_type in ('TimeField', ):
result = widgets.TimeWidget
elif internal_type in ('DurationField', ):
result = widgets.DurationWidget
elif internal_type in ('FloatField',):
result = widgets.FloatWidget
elif internal_type in ('IntegerField', 'PositiveIntegerField',
Expand Down
29 changes: 29 additions & 0 deletions import_export/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
except ImportError:
from django.utils.encoding import force_unicode as force_text

try:
from django.utils.dateparse import parse_duration
except ImportError:
# Duration fields were added in Django 1.8
pass


class Widget(object):
"""
Expand Down Expand Up @@ -230,6 +236,29 @@ def render(self, value, obj=None):
return value.strftime(self.formats[0])


class DurationWidget(Widget):
"""
Widget for converting time duration fields.
"""

def clean(self, value, row=None, *args, **kwargs):
if not value:
return None

try:
return parse_duration(value)
except NameError:
# Duration fields were added in Django 1.8
raise RuntimeError("Duration parsing not supported.")
except (ValueError, TypeError):
raise ValueError("Enter a valid duration.")

def render(self, value, obj=None):
if not value:
return ""
return str(value)


class SimpleArrayWidget(Widget):
def __init__(self, separator=None):
if separator is None:
Expand Down
26 changes: 25 additions & 1 deletion tests/core/tests/widgets_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from __future__ import unicode_literals

from decimal import Decimal
from datetime import date, datetime, time
from datetime import date, datetime, time, timedelta
from unittest import SkipTest

from django.test.utils import override_settings
from django.test import TestCase
Expand Down Expand Up @@ -107,6 +108,29 @@ def test_clean(self):
self.assertEqual(self.widget.clean("20:15:00"), self.time)


class DurationWidgetTest(TestCase):

def setUp(self):

try:
from django.utils.dateparse import parse_duration
except ImportError:
# Duration fields were added in Django 1.8
raise SkipTest

self.duration = timedelta(hours=1, minutes=57, seconds=0)
self.widget = widgets.DurationWidget()

def test_render(self):
self.assertEqual(self.widget.render(self.duration), "1:57:00")

def test_render_none(self):
self.assertEqual(self.widget.render(None), "")

def test_clean(self):
self.assertEqual(self.widget.clean("1:57:00"), self.duration)


class DecimalWidgetTest(TestCase):

def setUp(self):
Expand Down