Last active
November 4, 2015 21:48
-
-
Save jdunck/964a64bb4b03fc76f8ef to your computer and use it in GitHub Desktop.
Better Choices for django
This file contains hidden or 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
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()) |
This file contains hidden or 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
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') | |
] |
This file contains hidden or 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
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.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You might prefer https://django-model-utils.readthedocs.org/en/latest/utilities.html#choices