Skip to content

Instantly share code, notes, and snippets.

@jdunck
Last active November 4, 2015 21:48
Show Gist options
  • Save jdunck/964a64bb4b03fc76f8ef to your computer and use it in GitHub Desktop.
Save jdunck/964a64bb4b03fc76f8ef to your computer and use it in GitHub Desktop.
Better Choices for django
from collections import OrderedDict
class Choices(object):
"""
Just like raw tuple-choices you're used to passing to django's
choices kwarg, but better.
:param value_label_pairs: tuple-of-pairs, like raw choices= parameters.
:param attrs: optional attribute names to use instead of label.upper()
If your labels are invalid attribute names (as in "Purchase Order"),
you can supply another attrs argument (in the same order as the choices).
"""
def __init__(self, value_label_pairs, attrs=None):
self.pairs = OrderedDict(value_label_pairs)
self._label_to_value = OrderedDict([(v, k) for k, v in self.pairs.items()])
for index, (value, label) in enumerate(self.pairs.items()):
if attrs is None:
attr = label.upper()
else:
attr = attrs[index]
setattr(self, attr, value)
def label_to_value(self, label):
return self._label_to_value[label]
def value_to_label(self, value):
return self.pairs[value]
def offset(self, value):
matching_index = [index for index, v in enumerate(self.pairs.values()) if v == value]
if matching_index:
return matching_index[0]
else:
raise ValueError("%s is not a valid value" % value)
def items(self):
return self.pairs.items()
def __iter__(self):
return iter(self.pairs.items())
PUBLICATION_STATUSES = Choices([
(0, 'rough'),
(1, 'edit_ready'),
(2, 'edited'),
(3, 'approved'),
(4, 'published')
])
publication_status = IntegerField(choices=PUBLICATION_STATUSES)
PUBLICATION_STATUSES.ROUGH -> 0
PUBLICATION_STATUSES.value_to_name(1) -> 'edit_ready'
PUBLICATION_STATUSES.offset(2) -> 2 # tells you what index to select based on the desired constant value.
PUBLICATION_STATUSES.items() -> [
(0, 'rough'),
(1, 'edit_ready'),
(2, 'edited'),
(3, 'approved'),
(4, 'published')
]
class ChoicesTestCase(SimpleTestCase):
def test_simple_choices(self):
pairs = (
('value1', 'label1'),
('value2', 'label2')
)
choices = Choices(pairs)
self.assertEqual(choices.LABEL1, "value1")
self.assertEqual(choices.LABEL2, "value2")
self.assertEqual(choices.value_to_label('value1'), 'label1')
self.assertEqual(choices.label_to_value('label1'), 'value1')
self.assertEqual(choices.offset('label1'), 0)
with self.assertRaises(ValueError):
choices.offset('bad_label')
self.assertEqual(list(choices), list(pairs),
"Expected iter of Choices to match given pairs.")
def test_attr_override(self):
pairs = (
('value1', 'label1'),
('value2', 'label2')
)
choices = Choices(pairs, ('attr1', 'attr2'))
self.assertEqual(choices.attr1, "value1")
self.assertEqual(choices.attr2, "value2")
self.assertEqual(choices.value_to_label('value1'), 'label1')
self.assertEqual(choices.label_to_value('label1'), 'value1')
self.assertEqual(choices.offset('label1'), 0)
with self.assertRaises(ValueError):
choices.offset('bad_label')
self.assertEqual(list(choices), list(pairs),
"Expected iter of Choices to match given pairs.")
@jdunck
Copy link
Author

jdunck commented Nov 4, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment