Home » Django » Django model field choices – wouldn't a dict be better?

Django model field choices – wouldn't a dict be better?

Posted by: admin December 31, 2017 Leave a comment

Questions:

Given a field;

domain_status_choices = (
    (1,'Live')
    (2,'Offline')
    (3,'Dev')
)
status = models.SmallIntegerField( choices=domain_status_choices )

I know I can get and set numeric representation and use get_status_display() to get the text label. But if a user posts status=Offline how can I get the numeric value in order to save it? I’d also like to be able to validate that numbers or text values are in the list.

To me it makes more sense to use a dict. Here’s my current method;

domain_status_choices = {
    1: 'Live',
    2: 'Offline',
    3: 'Dev',
}
status = models.SmallIntegerField( choices=domain_status_choices.iteritems() )
...
if input1 not in domain_status_choices.keys(): print "invalid"
if input2 not in domain_status_choices.items(): print "invalid"
status = [k for k, v in domain_status_choices.iteritems() if v == input3][0]

Is there a better way? Why is a tuple of tuples usually used?

Answers:

I believe the keys of a dict are not guaranteed to be sorted (unless you use OrderedDict obviously). That is, you “might” get “Offline”, “Dev”, “Live” choices with your version.

Implementation note on dict.items:

Keys and values are listed in an arbitrary order which is non-random, varies across Python implementations, and depends on the dictionary’s history of insertions and deletions.

Questions:
Answers:

Expanding on my comment on @vicvicvic’s answer:

t = [ 'Live', 'Offline', 'Dev', ]
status = models.SmallIntegerField( choices=[(i,t[i]) for i in range(len(t))] )
...
if not 0 <= int(input1) < len(t): print "invalid"
if input2 not in t: print "invalid"
status = t.index(input2)