added ChoiceEnum

This commit is contained in:
Carl Meyer 2010-01-12 21:47:28 -05:00
parent e585513529
commit a2dcac06de
3 changed files with 88 additions and 0 deletions

View file

@ -28,6 +28,35 @@ Dependencies
.. _Django: http://www.djangoproject.com/
ChoiceEnum
==========
``ChoiceEnum`` makes setting ``choices`` on a Django model field way
too easy::
from model_utils import ChoiceEnum
class Article(models.Model):
STATUS = ChoiceEnum('draft', 'published')
# ...
status = models.PositiveIntegerField(choices=STATUS, default=STATUS.draft)
def status_desc(self):
return self.STATUS[self.status]
A ``ChoiceEnum`` object is initialized with any number of choices,
which should be strings. It assigns a sequential id to each
choice. The numerical id for a choice is available through attribute
access (``STATUS.draft``), and the text name for a choice can be
obtained by indexing with the numerical id
(``self.STATUS[self.status]``). If iterated over, a ``ChoiceEnum``
object yields a tuple of two-tuples linking id to text names, the
format expected by the ``choices`` attribute of Django models.
Be careful not to add new choices in the middle of the list, as that
will change the numerical ids for all subsequent choices, which could
impact existing data.
models.InheritanceCastModel
===========================

View file

@ -0,0 +1,45 @@
class ChoiceEnum(object):
"""
A class to encapsulate handy functionality for lists of choices
for a Django model field.
Accepts verbose choice names as arguments, and automatically
assigns numeric keys to them. When iterated over, behaves as the
standard Django choices tuple of two-tuples.
Attribute access allows conversion of verbose choice name to
choice key, dictionary access the reverse.
Example:
>>> STATUS = ChoiceEnum('DRAFT', 'PUBLISHED')
>>> STATUS.DRAFT
0
>>> STATUS[1]
'PUBLISHED'
>>> tuple(STATUS)
((0, 'DRAFT'), (1, 'PUBLISHED'))
"""
def __init__(self, *choices):
self._choices = tuple(enumerate(choices))
self._choice_dict = dict(self._choices)
self._reverse_dict = dict(((i[1], i[0]) for i in self._choices))
def __iter__(self):
return iter(self._choices)
def __getattr__(self, attname):
try:
return self._reverse_dict[attname]
except KeyError:
raise AttributeError(attname)
def __getitem__(self, key):
return self._choice_dict[key]
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__,
', '.join(("'%s'" % i[1] for i in self._choices)))

View file

@ -1,9 +1,23 @@
from django.test import TestCase
from django.contrib.contenttypes.models import ContentType
from model_utils import ChoiceEnum
from model_utils.tests.models import InheritParent, InheritChild, TimeStamp, \
Post
class ChoiceEnumTests(TestCase):
def setUp(self):
self.STATUS = ChoiceEnum('DRAFT', 'PUBLISHED')
def test_getattr(self):
self.assertEquals(self.STATUS.DRAFT, 0)
def test_getitem(self):
self.assertEquals(self.STATUS[1], 'PUBLISHED')
def test_iteration(self):
self.assertEquals(tuple(self.STATUS), ((0, 'DRAFT'), (1, 'PUBLISHED')))
class InheritanceCastModelTests(TestCase):
def setUp(self):
self.parent = InheritParent.objects.create()