django:循环或迭代字段,name和verbose_name

时间:2012-08-04 11:04:52

标签: django python-2.7 django-views django-templates

我想我已经阅读了大部分“相关/重复”的问题(例如verbose from template-tagiterate over field namesiterate through modelsfew,{{3 }})...)

不幸的是,我担心我需要一些手握......因为我是django n00b并且似乎无法使它工作。这是我想要的结果:

<!-- this in some section of the template -->
First Name : . Joe
Last Name : .. Blogs

<!-- this in another section -->
City:  ....... Xanadu
Country: ..... Mongolia
Occupation: .. Programmer

<!-- this in another section of the template -->
Age: ......... 75 
Height: ...... 180 cm
Eye color:  .. red

有4个或5个部分和10个可能的字段,我不想只做

{% if data.first_name %}
  First Name:  {{ data.first_name }}
{% endif %}
四十次! : - / ...所以这是(大致)我的尝试:

model.py

class GenericPerson(models.Model):
    first_name = models.CharField(_('First Name'),
                        max_length = 200, 
                        help_text = _('What is your name?'))

    last_name = models.CharField(_('Last Name'),
                        max_length = 200, 
                        help_text = _('What is your name?'))
    etc, etc ...

    class Meta:
        abstract = True

class Person(GenericPerson):    
    age_in_years = models.PositiveIntegerField(_('Age'), 
                null = True,
                blank = True,
                help_text=_('When was you born?, mate')) 
    location = models.ForeignKey(GeographicalProfile,
                               verbose_name=_('geolocations'),
                               null = True,
                               blank = True)

    height = ... etc, etc.

views.py

...
try:
   person = Person.objects.filter(pk=product_id)
except Person.DoesNotExist:
    raise Http404

generaldata = person.values('first_name',
                              'last_name',
                              etc, etc,
                              )[0]
localdata = person.values('city',
                              'country',
                              etc, etc
                              )[0]
physicaldata = person.values('age',
                                 'height',
                                 'eye_color',
                                  etc, etc
                                 )[0]
extra_context[data] = generaldata
extra_context[loc] = localdata
extra_context[phys] = physicaldata

return render_to_response(template_name, extra_context ,context_instance=RequestContext(request))

使用该视图,我可以

template.html

{% for p in phys.items %}
<ul>
  {% if p.1 %}
     <li>{{p.0}} :  {{p.1}}</li>
  {% endif %}
</ul>
{% endfor %}

适用于不同的部分。但是这会将字段作为age_in_years,eye_color(而不是名称)返回。好的,所以从上面的帖子中我创建了一个自定义模板标签,

from django import template
register = template.Library()

@register.filter
def get_name(object):
    return object._meta.verbose_name # put here whatever you would like to return

register.tag('get_name', get_name)

,将其加载到模板{%load person_extras%}中,现在......我已经盲目地在模板中的任何地方使用此{{something | get_object_name}} ...但是我的蛮力没有理解就给了我:

  

'str'对象没有属性'_meta'

     

'list'对象没有属性'_meta'

     

'tuple'对象没有属性'_meta'

     

'dict'对象没有属性'_meta'

     

'ValuesQuerySet'对象没有属性'_meta'

那么,我在哪里使用这个模板标签?或者如何修改我的视图以在for循环中使用此模板标记?

感谢您的见解

1 个答案:

答案 0 :(得分:3)

当您致电person = Person.objects.filter(pk=product_id)时,将返回QuerySetPeople个对象。当您随后在此查询集上使用values时 - 用文档的话语:

  

返回一个ValuesQuerySet - 一个QuerySet子类,当用作可迭代的而不是模型实例对象时返回字典。

所以基本上,在您尝试调用模板标记的模板中,您试图在字典对象而不是._meta.verbose_name对象上调用Person,这将无效。

所以,你可以做的只是将普通的查询集传递给模板,然后限制你想要为每个部分显示的字段(一般,本地,物理),并使用一些模板过滤器来帮助你。如下所示:

try:
    people = Person.objects.filter(pk=product_id)
except Person.DoesNotExist:
    raise Http404

extra_context = {
    'people' : people,
    'general_fieldnames' : ['first_name', 'last_name' ...],
    'local_fieldnames' : ['age', 'weight' ...],
    'physical_fieldnames' : ['age', 'height' ...], 
}
return render_to_response(template_name, extra_context      
    ,context_instance=RequestContext(request))

虽然存在问题(如您所知),因为没有简单的方法来遍历对象的字段,或者获取其详细的名称。相反,我们可以遍历我们的physical_fieldnames列表,从对象中获取相应的字段,并使用过滤器来表示详细的名称。

from django import template
register = template.Library()

@register.filter
def get_field_value(obj, field_name):
    return getattr(obj, field_name, None)

@register.filter
def get_verbose_name(obj, field_name):
    return obj._meta.get_field(field_name).verbose_name

register.tag('get_verbose_name', get_verbose_name)
register.tag('get_field_value', get_field_value)

现在在模板中

{% for person in people %}
<h1>General</h1>
<ul>
{% for field_name in general_fieldnames %}
    {{ person|get_verbose_name:field_name }} : {{ person|get_field_value:field_name }}
{% endfor %}
</ul>
{% endfor %}

...