Skip to content

Commit

Permalink
Merge pull request #575 from amalgamated-cc/durationfield_widget
Browse files Browse the repository at this point in the history
Add support for the Django DurationField with DurationWidget.
  • Loading branch information
bmihelac committed Feb 27, 2017
2 parents 378b830 + 51a0ba2 commit 96c632d
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 1 deletion.
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

0 comments on commit 96c632d

Please sign in to comment.