« We see no silver bullet | Main | links for 2007-02-07 »

django: display the name of a choice field instead of its value

Sometimes in django, you want to display a field choice's name and not the choice value (which is usually an integer). Here's one way to do that.

Function:

def get_choicename(obj, fieldname):
    """
    given an object and a field which has a choices argument, 
    find the name of choice for that field instead of its stored 
    database number svalue
    
    returns the tuple ( '$field$_choicename', field_choicename
    """    
    field_key=int(getattr(obj, fieldname))
    field = obj._meta.get_field(fieldname) #*
    field_choicename=[val for key,val in field.choices if key==field_key][0]
    return '%s_choicename'%fieldname, field_choicename

Example:

from utils import get_choicename

class MessageTracking(models.Model):
    """
    """
    STATUS_CHOICES = (
        (MessageTrackingState.UNKNOWN, 'unknown'),
        (MessageTrackingState.OPEN, 'open'),
        (MessageTrackingState.SENT, 'sent'),
        (MessageTrackingState.RECEIPTED, 'receipted'),
        (MessageTrackingState.CANCELLED, 'cancelled'),
        (MessageTrackingState.OVERDUE, 'overdue'),
    )
    uid = models.CharField(maxlength=48, default="", blank=True, db_index=True) 
    date_received =  models.DateTimeField(db_index=True, blank=True)
    date_sent =  models.DateTimeField(null=True, blank=True, db_index=True)
    date_sent_expected =  models.DateTimeField(null=True, blank=True, db_index=True)
    status = models.PositiveIntegerField(choices=STATUS_CHOICES, default=0, blank=True, db_index=True)
    insert_time = models.DateTimeField(auto_now_add=True, db_index=True, editable=False)

    def status_nicename(self):
        return get_choicename(self, "status")[1]


{% block content %}
<h2 class="pagetitle">Serial No: {{ object.uid }}</h3>
<p>date received: {{ object.date_received }}</p>
<p>date sent: {{ object.date_sent }}</p>
<p>date sent_expected: {{ object.date_sent_expected }}

<p>status: {{ object.status_nicename }}</p> {% endblock %}

#* Indeed, there's a whole meta layer in there.


February 7, 2007 12:35 AM

Comments

Malcolm Tredinnick
(February 7, 2007 07:37 AM #)

Isn't this the same as the get_status_display() method (for the "status" field)? The DB">http://www.djangoproject.com/documentation/db_api/#get-foo-display">DB API documentation discusses these automatically created methods.

I have a feeling we've not made some of that stuff as clear as it should be (e.g. by including a reference at the same place that "choices" is discussed) in the Django docs.

Bill de hOra
(February 7, 2007 10:18 AM #)

"Isn't this the same as the get_status_display() method (for the "status" field)?"

I'll check; I wrote this after an irc session on #django; no-one seemed to have a quick to write out the value/name for a choice.

"I have a feeling we've not made some of that stuff as clear as it should be"

Maybe. It was a surprise to me initially there was a meta layer in there.

Malcolm Tredinnick
(February 7, 2007 11:00 AM #)

The _meta attribute you draw attention to is not intended to be exposed (hence the leading underscore). So the main Django documentation does not mention it at all, as we don't have a "Deep, Dark Internals For Framework Developers Only" document (yet).

It would be interesting to know if there is a genuine need for exposing this information. I've come across some need to do so in my own fiddling in order to get access to the database field and table names for a model field in a portable fashion. I haven't seen a lot of people wanting to dive in that deep, though (am I the only person writing multi-database-compatible code? I doubt it), so it hasn't really surfaced in my mind as something we need to look at. Willing and interested to be convinced I'm wrong here.

James Bennett
(February 8, 2007 05:22 AM #)

This is on my hit list of "common questions we do a crappy job of answering in the official docs", and I've filed a reminder of it in ticket 3455:

http://code.djangoproject.com/ticket/3455

@Malcolm: I'm working on an app which makes use of _meta to get table names for some custom queries, so you're not the only one. Feel like writing a companion to your explanation of the model metaclass and delving into the innards of _meta and the Options class? For bonus points, document get_model() as well... :)

Bill de hOra
(February 8, 2007 01:10 PM #)

"Willing and interested to be convinced I'm wrong here."

It's hard to say. A 30 minute session in ipython and I had a good enough solution. Yes, it would be nice to have the convenience calls against the meta layer, but everyone will have some kind of need, they won't all be the same. I think you only have to look at some established frameworks (*cough*Zope*cough*, *cough*Rails 2 years from now*cough*) to see where exposing the meta layer early on as a *feature* ends up - too much magic.

Post a comment

(you may use HTML tags for style)




Remember Me?

Trackback Pings

TrackBack URL for this entry:
http://www.dehora.net/mt/mt-tb.cgi/2036