Skip to content

Commit

Permalink
Merge pull request #14 from seawolf42/feature/rest-framework-serializ…
Browse files Browse the repository at this point in the history
…er-field

Feature/rest framework serializer field
  • Loading branch information
seawolf42 committed Jun 14, 2018
2 parents 80d05c3 + f926236 commit 0df293d
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 2 deletions.
45 changes: 45 additions & 0 deletions lookup_tables/drf_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from lookup_tables.models import LookupTableItem
from rest_framework import fields
import six


class LookupTableItemSerializerField(fields.ChoiceField):

def __init__(self, table_ref, **kwargs):
self._table_ref = table_ref
self._choices = None
super(LookupTableItemSerializerField, self).__init__([], **kwargs)
self._reset_choices()

def to_internal_value(self, data):
if data == '' and self.allow_blank:
return None
self._reset_choices()
try:
return LookupTableItem.objects.get(
table__table_ref=self._table_ref,
id=self.choice_strings_to_values[six.text_type(data)],
)
except (KeyError, LookupTableItem.DoesNotExist):
self.fail('invalid_choice', input=data)

def to_representation(self, value):
if value is None:
return value
return super(LookupTableItemSerializerField, self).to_representation(value.name)

def iter_options(self):
"""
Helper method for use with templates rendering select widgets.
"""
self._reset_choices()
return super(LookupTableItemSerializerField, self).iter_options()

def _reset_choices(self):
self._choices = None
self._set_choices(self._get_choices())

def _get_choices(self):
if self._choices is None or len(self._choices) == 0:
self._choices = [(i.id, i.name) for i in LookupTableItem.objects.filter(table__table_ref=self._table_ref)]
return self._choices
9 changes: 7 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@
'Django>=1.8' + (',<1.11.99' if sys.version_info[0] < 3 else ''),
)

test_dependencies = (
'mock',
'djangorestframework',
)


setup(
name='django-lookup-tables',
version='0.11.1',
version='0.12.0',
packages=find_packages(),
include_package_data=True,
license='MIT License',
Expand Down Expand Up @@ -51,6 +56,6 @@
'Programming Language :: Python :: 3.6',
],
install_requires=install_dependencies,
tests_require=install_dependencies + ('mock',),
tests_require=install_dependencies + test_dependencies,
test_suite='runtests.run_tests',
)
84 changes: 84 additions & 0 deletions tests/test_drf_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import sys

from django.test import TestCase
from rest_framework.exceptions import ValidationError

from lookup_tables.drf_fields import LookupTableItemSerializerField

from .utils import strings

if sys.version_info[0] < 3:
# python 2
import mock
else:
# python 3
from unittest import mock


class MockLTI(object):

def __init__(self, id):
self.id = id
self.name = str(id)


class LookupTableItemSerializerFieldTest(TestCase):

@mock.patch('rest_framework.fields.ChoiceField.__init__')
@mock.patch('lookup_tables.drf_fields.LookupTableItemSerializerField._reset_choices')
def test_init(self, mock_reset_choices, mock_parent_init):
item = LookupTableItemSerializerField(strings[0], x=strings[-1], y=strings[-2])
mock_parent_init.assert_called_once_with([], x=strings[-1], y=strings[-2])
mock_reset_choices.assert_called_once_with()
self.assertEqual(item._table_ref, strings[0])
self.assertEqual(item.choices, None)

def test_to_internal_value_handles_empty_reply(self):
item = LookupTableItemSerializerField(strings[0], allow_blank=True)
self.assertIsNone(item.to_internal_value(''))

@mock.patch('lookup_tables.drf_fields.LookupTableItem')
def test_to_internal_value_sets_choices(self, mock_lti):
lti_get_return_value = mock.MagicMock()
mock_lti.objects.get.return_value = lti_get_return_value
lti_filter_return_value = [MockLTI(i) for i in range(3)]
mock_lti.objects.filter.return_value = lti_filter_return_value
item = LookupTableItemSerializerField(strings[0])
result = item.to_internal_value('1')
self.assertEqual(result, lti_get_return_value)
mock_lti.objects.get.assert_called_once_with(table__table_ref=item._table_ref, id=1)

@mock.patch('lookup_tables.drf_fields.LookupTableItem')
def test_to_internal_value_invalid_value(self, mock_lti):
mock_lti.objects.filter.return_value = [MockLTI(i) for i in range(3)]
mock_lti.DoesNotExist = Exception
item = LookupTableItemSerializerField(strings[0])
with self.assertRaises(ValidationError):
item.to_internal_value('1000')

@mock.patch('lookup_tables.drf_fields.LookupTableItem')
def test_to_internal_value_invalid_table_id(self, mock_lti):
mock_lti.objects.filter.return_value = [MockLTI(i) for i in range(3)]
mock_lti.DoesNotExist = Exception
mock_lti.objects.get.side_effect = Exception
item = LookupTableItemSerializerField(strings[0])
with self.assertRaises(ValidationError):
item.to_internal_value('1')

def test_to_representation(self):
item = LookupTableItemSerializerField(strings[0])
self.assertEqual(item.to_representation(MockLTI(1)), '1')

@mock.patch('lookup_tables.drf_fields.LookupTableItemSerializerField._get_choices')
@mock.patch('lookup_tables.drf_fields.LookupTableItemSerializerField._set_choices')
def test_reset_choices(self, mock_set_choices, mock_get_choices):
mock_get_choices.return_value = []
item = LookupTableItemSerializerField(strings[0])
item._choices = strings[0]
mock_get_choices.return_value = strings[1]
mock_get_choices.reset_mock()
mock_set_choices.reset_mock()
item._reset_choices()
self.assertEqual(item._choices, None)
mock_get_choices.assert_called_once_with()
mock_set_choices.assert_called_once_with(strings[1])

0 comments on commit 0df293d

Please sign in to comment.