2009-05-10 2 views
36

Метод getattr() Python полезен, если вы заранее не знаете имя определенного атрибута.Выполнение поиска стиля getattr() в шаблоне django

Эта функциональность также пригодится в шаблонах, но я никогда не выяснил, как это сделать. Есть ли встроенный тег или не встроенный тег, который может выполнять динамический поиск атрибутов?

+0

Интересно, пытаетесь ли вы сделать слишком много в своих шаблонах. getattr иногда чувствует себя как черная магия в коде Python, так что это, безусловно, запах кода в шаблоне! –

ответ

53

Я также получил write this code в качестве пользовательского тега шаблона. Чтобы обрабатывать все сценарии поиска, он сначала выполняет поиск стандартного атрибута, затем пытается выполнить поиск по словарю, затем пытается найти getitem (для работы списков), затем следует стандартное поведение шаблона Django, когда объект не найден.

(обновлена ​​2009-08-26 в настоящее обрабатывать Lookups индекса списка, а) использование

# app/templatetags/getattribute.py 

import re 
from django import template 
from django.conf import settings 

numeric_test = re.compile("^\d+$") 
register = template.Library() 

def getattribute(value, arg): 
    """Gets an attribute of an object dynamically from a string name""" 

    if hasattr(value, str(arg)): 
     return getattr(value, arg) 
    elif hasattr(value, 'has_key') and value.has_key(arg): 
     return value[arg] 
    elif numeric_test.match(str(arg)) and len(value) > int(arg): 
     return value[int(arg)] 
    else: 
     return settings.TEMPLATE_STRING_IF_INVALID 

register.filter('getattribute', getattribute) 

Шаблон:

{% load getattribute %} 
{{ object|getattribute:dynamic_string_var }} 


+0

Блестящий - thankyou! – starsinmypockets

+0

Мне что-то не хватает - какова цель второй и третьей статей? Если 'hasattr (value, 'has_key')', то вы не можете получить к нему доступ в шаблоне, используя 'value.arg'? Аналогично, если это массив, 'value.i' получает i-й элемент. Это просто так, что функция обрабатывает эти избыточные случаи? – Symmetric

+1

Существуют такие удобства, чтобы имитировать поведение шаблонов Django - когда вы выполняете '{{value.arg}}', Django проверяет, является ли это атрибутом объекта (раздел 1), словарным ключом (раздел 2), индексом списка (раздел 3), а затем по умолчанию доходит до пустой строки.Итак, да, '{{значение | getattribute: dynamic_arg_name}}' не является «getattribute» в самом чистом смысле Python, но он ведет себя так же, как обычные Django-запросы. – fotinakis

2

Я так не думаю. Но было бы нелегко написать custom template tag, чтобы вернуть атрибут в контексте dict. Если вы просто пытаетесь вернуть строку, попробовать что-то вроде этого:

class GetAttrNode(template.Node): 
    def __init__(self, attr_name): 
     self.attr_name = attr_name 

    def render(self, context): 
     try: 
      return context[self.attr_name] 
     except: 
      # (better yet, return an exception here) 
      return '' 

@register.tag 
def get_attr(parser, token): 
    return GetAttrNode(token) 

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

2

Я закончил тем, что добавил метод к рассматриваемой модели, и этот метод можно получить как атрибут в шаблоне.

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

2

Сохраняя различие между получить и GetAttr,

@register.filter(name='get') 
def get(o, index): 
    try: 
     return o[index] 
    except: 
     return settings.TEMPLATE_STRING_IF_INVALID 


@register.filter(name='getattr') 
def getattrfilter(o, attr): 
    try: 
     return getattr(o, attr) 
    except: 
     return settings.TEMPLATE_STRING_IF_INVALID 
0

Этот сниппет сохранил мой день, но мне это нужно, чтобы охватить его отношениями, поэтому я изменил его, чтобы разделить arg на «.». и рекурсивно получить значение. Это можно сделать в одной строке: return getattribute(getattribute(value,str(arg).split(".")[0]),".".join(str(arg).split(".")[1:])) , но я оставил его в 4 для удобства чтения. Надеюсь, у кого-то есть это.

import re 
from django import template 
from django.conf import settings 

numeric_test = re.compile("^\d+$") 
register = template.Library() 

def getattribute(value, arg): 
"""Gets an attribute of an object dynamically AND recursively from a string name""" 
    if "." in str(arg): 
     firstarg = str(arg).split(".")[0] 
     value = getattribute(value,firstarg) 
     arg = ".".join(str(arg).split(".")[1:]) 
     return getattribute(value,arg) 
    if hasattr(value, str(arg)): 
     return getattr(value, arg) 
    elif hasattr(value, 'has_key') and value.has_key(arg): 
     return value[arg] 
    elif numeric_test.match(str(arg)) and len(value) > int(arg): 
     return value[int(arg)] 
    else: 
     #return settings.TEMPLATE_STRING_IF_INVALID 
     return 'no attr.' + str(arg) + 'for:' + str(value) 

register.filter('getattribute', getattribute) 
Смежные вопросы