django: display the name of a choice field instead of its value
February 07, 2007 |
co.mments
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
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.
"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.
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.
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... :)
"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
Trackback Pings
TrackBack URL for this entry:
http://www.dehora.net/mt/mt-tb.cgi/2036