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 2 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
- Help text hyperlinks by sa2812 11 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.