get_FOO_display() for generic/variable choice fields

908 views
Skip to first unread message

katstevens

unread,
Jan 24, 2012, 6:51:27 AM1/24/12
to Django users
I have a model ContactDetail with two choice fields,
ContactDetail.dialing_code and ContactDetail.country. These use the
standard tuples ('AU', 'Australia') and so on.

I know I can use get_country_display() and get_dialing_code_display()
to show the longer values, but is there a more generic version where
the field name is replaced with a variable?

For example, I want to create a customised .csv file from the model
data. I can loop through the fields from my model and get the shorter
attribute values without any problems. However I'd like to do
something like this:

obj = queryset[my_item] # an instance of ContactDetail()
model = queryset.model # ContactDetail() itself

for field in model._meta.fields:
val = getattr(obj, field.name) # gets the shorter version
if field.choices: # if field is ChoiceField, convert data
to display mode
val = obj.get_field_display()
row.append(val)

Obviously the 'val = obj.get_field_display()' line doesn't work!

Is there a generic way of doing this (something like
obj.get_display(fieldname) ?) or am I going to have to hard code
separate checks for get_country_display() and
get_dialing_code_display()?

Ideally I would like to use this particular function for other models
and keep the fields as generic as possible.

Bill Freeman

unread,
Jan 24, 2012, 1:21:14 PM1/24/12
to django...@googlegroups.com
Maybe try:

val = getattr(obj, 'get_%s_display' % field.name)()

> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To post to this group, send email to django...@googlegroups.com.
> To unsubscribe from this group, send email to
> django-users...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/django-users?hl=en.
>
>

katstevens

unread,
Jan 25, 2012, 5:21:50 AM1/25/12
to Django users
My Python-expert partner suggested a clever workaround as follows:

As I'm already running through the model._meta.fields beforehand to
create header row for my .csv file, I can build a dictionary of the
choices to refer to later.

choices_lookup_dict = {}
header_row = []

for field in model._meta.fields:
# create header row for csv file
header_row.append(field.name)
# Add lookup dictionary of choices to dictionary of fields
# i.e. creating a dictionary of dictionaries for each choice field
if field.choices:
choices_lookup_dict[field.name] = dict(field.choices)

This could be quite expensive for large choice tuples such as country
lists, but at least we're only calling it once.

So now in my main loop I can use the following code to lookup my
verbose choice value:


for field in model._meta.fields:
val = getattr(obj, field.name)
if field.choices:
val = choices_lookup_dict[field.name][val]
row.append(val)


We assume that get_FOO_display() must be doing something like this
anyway!

Michael Elkins

unread,
Jan 24, 2012, 12:54:48 PM1/24/12
to django...@googlegroups.com
On Tue, Jan 24, 2012 at 03:51:27AM -0800, katstevens wrote:
>Obviously the 'val = obj.get_field_display()' line doesn't work!
>
>Is there a generic way of doing this (something like
>obj.get_display(fieldname) ?) or am I going to have to hard code
>separate checks for get_country_display() and
>get_dialing_code_display()?

I think you can do what you want like this:

obj = queryset[my_item]

for field in obj._meta.fields:
if field.choices:
val = obj._get_FIELD_display(field)
else:
val = getattr(obj, field.name)
row.append(val)

Reply all
Reply to author
Forward
0 new messages