Шаблоны Django: прокручивать и печатать все доступные свойства объекта?

У меня есть объект базы данных с именем manor_stats, содержащий около 30 полей. Для большинства строк большинство этих полей будут нулевыми.

В моем шаблоне я хотел бы пройтись по всем полям в строке и распечатать информацию только для тех полей, которые не равны нулю.

Например, есть поле под названием «имя»: я хотел бы напечатать <li>Name: {{ manor_stats.name }}</li> в шаблоне ТОЛЬКО для тех объектов, где поле не равно нулю. В идеале я хотел бы получить «Имя:» откуда-то автоматически, а не указывать его.

Я знаю, что могу использовать {% if manor_stats.name %}, чтобы проверить, является ли каждое поле пустым, но я не хочу делать это 30 раз для всех полей.

Вот что у меня есть в views.py:

manor_stats = Manors.objects.get(idx=id)
return render_to_response('place.html', { 'place' : place, 'manor_stats' : manor_stats }, context_instance = RequestContext(request))

И затем в place.html я хотел бы иметь что-то, что работает примерно так (псевдокод, где ??? указывает на биты, которые я не знаю, как сделать):

{% if manor_stats %} 
<ul>
 {% for manor_stats.property??? in manor_stats %} 
  {% if manor_stats.property %} 
   <li>{{ manor_stats.property.field_name??? }} {{ manor_stats.property.value??? }}</li>
  {% endif %}
 {% endfor %
{% endif %}

Надеюсь, это имеет смысл...


person AP257    schedule 07.02.2010    source источник
comment
Точный дубликат: stackoverflow.com/questions/2170228/   -  person Ignacio Vazquez-Abrams    schedule 07.02.2010


Ответы (3)


Вы можете добавить метод в свою модель Manors, который будет возвращать все значения полей, оттуда вы можете просто перебирать эти значения в своем шаблоне, проверяя, не является ли значение нулевым.

-- models.py

class Manors(models.Model)
  #field declarations

  def get_fields(self):
    return [(field.name, field.value_to_string(self)) for field in Manors._meta.fields]

-- manor_detail.html

{% for name, value in manor_stats.get_fields %}
  {% if value %}
    {{ name }} => {{ value }}
  {% endif %}
{% endfor %}
person buckley    schedule 07.02.2010
comment
Работает отлично - именно то, что я искал. Спасибо! - person AP257; 07.02.2010
comment
Знаете ли вы, как я могу каким-то образом вернуть field.verbose_name вместе со значением? Я думаю, это просто вопрос правильного синтаксиса Django, но я сбит с толку :( - person AP257; 08.02.2010
comment
Я внес некоторые изменения в свой первоначальный ответ. Атрибут имени, прикрепленный к полю, должен дать вам то, что вы хотите. - person buckley; 08.02.2010
comment
Еще раз спасибо! Делает только то, что нужно. - person AP257; 08.02.2010
comment
Очень элегантный. Если вам нужно немного больше контроля (например, возможность разрешать поля списков выбора/выбора или исключать определенные поля, см. несколько более сложную версию метода модели, который получает все поля и возвращает их в шаблон: stackoverflow.com/questions/2170228/ - person shacker; 09.02.2010
comment
Для будущих читателей мне нужно изменить field.name на field.verbose_name. В противном случае на месте! - person thumbtackthief; 14.03.2014
comment
Как можно настроить метод так, чтобы он выбирал поля вместо того, чтобы захватывать все поля? - person Jay Jung; 07.02.2018

Следующий подход требует определения только одного пользовательского фильтра шаблона (см. документы) - это DRY'er, чем писать или копировать метод в каждую модель, для которой вам нужна эта функциональность.

-- my_app/templatetags/my_tags.py

from django import template

register = template.Library()

@register.filter
def get_fields(obj):
    return [(field.name, field.value_to_string(obj)) for field in obj._meta.fields]

Вам потребуется перезапустить сервер, чтобы новые теги были зарегистрированы и доступны в ваших шаблонах.

-- my_app/templates/my_app/my_template.html

{% load my_tags %}
<ul>
{% for key, val in object|get_fields %}
  <li>{{ key }}: {{ val }}</li>
{% endfor %}
</ul>

Протестировано в Джанго 1.11.

Примечание: поскольку ._meta является закрытым атрибутом, его функциональность может измениться в будущем.

Спасибо другим ответам на этот пост, которые помогли мне пройти большую часть пути, особенно В. Перрину.

person Rob Simpson    schedule 27.07.2018
comment
Я использовал return [(field.name, field.verbose_name, field.value_to_string(obj)) for field in obj._meta.fields] для отображения verbose_name, а не name в шаблоне. - person Rami Alloush; 03.09.2019

Используйте Model._meta.get_fields() в коде Python.

>>> from django.contrib.auth.models import User
>>> User._meta.get_fields()
(<ManyToOneRel: admin.logentry>,
 <django.db.models.fields.AutoField: id>,
 <django.db.models.fields.CharField: password>,
 <django.db.models.fields.DateTimeField: last_login>,
 <django.db.models.fields.BooleanField: is_superuser>,
....

В шаблоне мы можем определить фильтр для получения всех полей.

├─my_app
│  │
│  ├─templatetags
│  │  │  my_filters.py
│  │

from django import template
register = template.Library()

@register.filter
def get_fields(obj):
    return obj._meta.get_fields()

{% for k,v in obj|get_fields %}
    <td> {{k}} </td>
{% endfor %}

См. эту ссылку: https://docs.djangoproject.com/en/2.0/ref/models/meta/#retrieving-all-field-instances-of-a-model

person W.Perrin    schedule 26.05.2018