-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from seawolf42/feature/rest-framework-serializ…
…er-field Feature/rest framework serializer field
- Loading branch information
Showing
3 changed files
with
136 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]) |