Friday, April 1, 2011

Perfect choice

Have you ever wondered how to deal with django choices without hardcoding numeric values into code?


Well, I was wondering too, found some solutions on the Web but after all need some rewriting to came up with this:

class Enumeration(object):
 """
 A small helper class for more readable enumerations,
 and compatible with Django's choice convention.
 You may just pass the instance of this class as the choices
 argument of model/form fields.

 Example:
  MY_ENUM = Enumeration([
   (100, 'MY_NAME', 'My verbose name'),
   (200, 'MY_AGE', 'My verbose age'),
  ])
  assert MY_ENUM.MY_AGE == 100
  assert MY_ENUM[1] == (200, 'My verbose age')
 """

 def __init__(self, enum_list):
  self.enum_list_full=enum_list
  self.enum_list = [(item[0], item[2]) for item in enum_list]
  self.enum_dict = {}
  self.enum_display = {}
  for item in enum_list:
   self.enum_dict[item[1]] = item[0]
   self.enum_display[item[0]] = item[2]

 def __contains__(self, v):
  return (v in self.enum_list)

 def __len__(self):
  return len(self.enum_list)

 def __getitem__(self, v):
  if isinstance(v, basestring):
   return self.enum_dict[v]
  elif isinstance(v, int):
   return self.enum_list[v]

 def __getattr__(self, name):
  return self.enum_dict[name]

 def __iter__(self):
  return self.enum_list.__iter__()
 def __repr__(self):
  return 'Enum(%s)' % self.enum_list_full.__repr__()

 def get_display_name(self, v):
  return self.enum_display[v]

This is a little customization of this snippet: http://djangosnippets.org/snippets/1647/

How does it work with models? Nice and easy:

class SoomeModel(models.Model):
 OPTIONS=Enumeration([
   (1, OPTION_A, u'This is option A'),
   (2, OPTION_B, u'This is option B'),
   (3, OPTION_C, u'This is option C'),

  ])
 option = models.IntegerField(choices=OPTIONS)

Now you can use it like that:

>> SomeModel.OPTIONS.OPTION_A
.. 1
>> SomeModel.OPTIONS['OPTION_B']
.. 2
>> SomeModel.OPTIONS[1]
.. (2, 'This is option B')
>> SomeModel.OPTIONS.get_display_name(2)
.. "This is option B"
>> SomeModel.OPTIONS.get_display_name(SomeModel.OPTIONS_A)
.. "This is option A"

No more hardcoding values. No more!

No comments:

Post a Comment