9

I made up a template to show all the fields and values from a model, it looks like this:

## detail_template.html ##
{% for name, value in object.get_fields %}
    <p>
        <label>{% trans name %}:</label>
        <span>{{ value|default:"Not available" }}</span>
    </p>
{% endfor %}

In the class you can see the get_fields function declared:

## models.py ##
Class Object:
    ...many fields...

    def get_fields(self):
        return [(field.verbose_name, field._get_val_from_obj(self)) for field in self.__class__._meta.fields]

The problem is, when I have, for example, a CharField with choices, like:

## models.py ##
GENDER_CHOICES = (
    ('M', 'Male'),
    ('F', 'Female'),
)
        ...all other fields ...
    sex =   models.CharField(verbose_name=u"Sex", max_length=1, choices=GENDER_CHOICES)

It displays M or F, what I want to do is load the get_NAMEFIELD_display of all fields without doing manually all fields:

<p>
    <label>{% trans 'Sex' %}:</label>
    <span>{{ object.get_sex_display|default:"Not available" }}</span>
</p>

I have a clue: Django Contrib Admin does that when listing objects, so I'm sure there is a generic way of doing that and I also appreciate any help.

staticdev
  • 2,950
  • 8
  • 42
  • 66

2 Answers2

11

Django >= 2.0

field._get_val_from_obj() is removed in Django 2.0 use field.value_from_object() instead.

Add get_fields() to your models.py:

class Object(Model):
    field1 = CharField(max_length=150)
    field2 = CharField(max_length=150)

    def get_fields(self):
        return [(field.verbose_name, field.value_from_object(self)) for field in self.__class__._meta.fields]

Then call it as object.get_fields on your template.html:

<table>
    {% for label, value in object.get_fields %}
        <tr>
            <td>{{ label }}</td>
            <td>{{ value }}</td>
        </tr>
    {% endfor %}
</table>
JV conseil
  • 328
  • 5
  • 11
  • thanks @JV conseil; it works like a charm, for my model with over 50 fields. However, what can i do related to foreign key? I have a model with all relationship types, and i am not getting the value that i need on foreign key fields. For example, using your code, one row displays sales_agent = 6. I assume the number is the id of the sales agent (it is a match). How can i display the username of the sales agent?(custom user model has a boolean filed 'is_sales_agent') – Cornel Ciobanu Aug 29 '21 at 17:58
0

I think you should add another method:

def get_field_value(self, field):
    try:
        return self._get_FIELD_display(field)
    except something:
        return field._get_val_from_obj(self)

And use it in your generator.

ilvar
  • 5,718
  • 1
  • 20
  • 17
  • I see, I tried that.. it is calling all the get_field_displays, but now all the other fields that doesn't have the function are not returning the get_val_from_obj =( I need to know the exception it gives when there is no get_field_display – staticdev Apr 06 '12 at 15:24
  • Run Python shell, retrieve object and try to call `obj._get_FIELD_display('some_non_existent_field')` - you'll get the exception – ilvar Apr 07 '12 at 00:04
  • There is no need to add the other method, it raises no exception. If you call self._get_FIELD_display(field) if returns the value even if there is no get_field_display method =) – staticdev Apr 07 '12 at 17:06
  • 1
    I see, thanks. Than you can check type of `field` and choose the method according to it. – ilvar Apr 08 '12 at 03:17
  • I is still not working for get_field_display methods that I create, for example, I have a field status: `status = models.IntegerField(verbose_name=u"Status", db_index=True, default=1)` And I put in the model the method: `def get_status_display(self): if self.status == 1: return "Active" else: return "Inactive"` It continues to show 1 and 0. – staticdev Apr 11 '12 at 13:22
  • Why are you overriding `get_status_display` and not `_get_FIELD_display`? You can also check if the field has [flatchoices](https://code.djangoproject.com/browser/django/trunk/django/db/models/base.py#L580) – ilvar Apr 11 '12 at 16:27