This is a very flexible and concise way to Handle choices the right way in model fields.
- Preserves order.
- Allows both a human-readable value for display in form
<select>
s as well as a code-friendly short name. - Mimic's Django's canonical choices format.
- Doesn't restrict the value type.
- Memory efficient.
Inspired by snippet 2373 to use namedtuples as model field choices.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | try:
from collections import namedtuple
except ImportError:
# Python 2.4, 2.5 backport:
# http://code.activestate.com/recipes/500261/
from somewhere.my_namedtuple_backport import namedtuple
def get_namedtuple_choices(name, choices_tuple):
"""Factory function for quickly making a namedtuple suitable for use in a
Django model as a choices attribute on a field. It will preserve order.
Usage::
class MyModel(models.Model):
COLORS = get_namedtuple_choices('COLORS', (
(0, 'BLACK', 'Black'),
(1, 'WHITE', 'White'),
))
colors = models.PositiveIntegerField(choices=COLORS)
>>> MyModel.COLORS.BLACK
0
>>> MyModel.COLORS.get_choices()
[(0, 'Black'), (1, 'White')]
class OtherModel(models.Model):
GRADES = get_namedtuple_choices('GRADES', (
('FR', 'FR', 'Freshman'),
('SR', 'SR', 'Senior'),
))
grade = models.CharField(max_length=2, choices=GRADES)
>>> OtherModel.GRADES.FR
'FR'
>>> OtherModel.GRADES.get_choices()
[('FR', 'Freshman'), ('SR', 'Senior')]
"""
class Choices(namedtuple(name, [name for val,name,desc in choices_tuple])):
__slots__ = ()
_choices = tuple([desc for val,name,desc in choices_tuple])
def get_choices(self):
return zip(tuple(self), self._choices)
return Choices._make([val for val,name,desc in choices_tuple])
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Great idea!
1) You don't need to use
namedtuple
there, you can just usesetattr
on class to add methods after class creation, and very simple__str__
method (exactly what nametuple backport snippet does).2) Why do I need to write name of choices group twice?
#
I'm subclassing
namedtuple
because it avoids the extra boilerplate that rolling your ownsetattr
class requires and allows a clean and full-featured choices solution in seven lines of code. :)Read the examples in the docstring. It is setting
(value, code-friendly name, human-readable name)
.#
I don't get how that is better than the common way of defining choices.
#
Read James Bennett's blog post linked in the snippet description. Also look at the dozen or so other implementations on this site.
#
Please login first before commenting.