2009-05-10 18 views
36

Metoda getattr() Pythona jest przydatna, gdy nie znasz wcześniej nazwy określonego atrybutu.Wykonywanie przeszukiwania stylu getattr() w szablonie django

Ta funkcja przydałaby się również w szablonach, ale nigdy nie wymyśliłem sposobu, aby to zrobić. Czy istnieje wbudowany tag lub niezamontowany tag, który może wykonywać dynamiczne wyszukiwania atrybutów?

+0

Zastanawiam się, czy próbujesz zrobić za dużo w swoich szablonach. getattr czasami czuje się jak czarna magia w kodzie Pythona, więc z pewnością jest to zapach kodu w szablonie! –

Odpowiedz

53

Niedawno również miałem do write this code jako niestandardowy tag szablonu. Aby obsłużyć wszystkie scenariusze wyszukiwania, najpierw wykonuje standardowe wyszukiwanie atrybutów, następnie próbuje wyszukać słownik, a następnie próbuje wyszukać (aby listy działały), a następnie postępuje zgodnie ze standardowym zachowaniem szablonu Django, gdy obiekt nie został znaleziony.

(aktualizacja 2009-08-26 do teraz obsługiwać wyszukiwań Index Lista również) Wykorzystanie

# 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) 

Szablon:

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


+0

Brilliant - thankyou! – starsinmypockets

+0

Brakuje mi czegoś tutaj - jaki jest cel drugiego i trzeciego zdania? Jeśli 'hasattr (value, 'has_key')', to czy nie możesz uzyskać do niego dostęp w szablonie używając 'value.arg'? Podobnie, jeśli jest to tablica, 'value.i' pobiera i'th element. Czy te właśnie funkcje obsługują te zbędne przypadki? – Symmetric

+1

Są to wygody naśladujące szablony Django zachowania - kiedy robisz '{{value.arg}}', Django sprawdza, czy jest to atrybut obiektu (klauzula 1), klucz słownika (klauzula 2), indeks listy (klauzula 3), a następnie domyślnie przechodzi do pustego łańcucha.Więc tak, '{{value | getattribute: dynamic_arg_name}}' nie jest "getattribute" w najczystszym sensie Pythona, ale zachowuje się tak samo, jak normalne odnośniki Django. – fotinakis

2

Nie sądzę. Ale nie byłoby zbyt trudno napisać custom template tag, aby zwrócić atrybut w kontekście dict. Jeśli jesteś po prostu stara się zwracać ciąg, spróbuj coś takiego:

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) 

Należy pamiętać, że jest to prawdopodobnie tak łatwo to zrobić w widoku zamiast w szablonie, chyba że jest to stan, który jest powtarzany często w twoich danych.

2

Skończyłem na dodaniu metody do danego modelu, a ta metoda może być dostępna jak atrybut w szablonie.

Nadal uważam, że byłoby wspaniale, gdyby wbudowany tag pozwalał dynamicznie wyszukiwać atrybuty, ponieważ jest to problem, który wielu z nas ciągle ma w naszych szablonach.

2

Utrzymanie rozróżnienie między dostać i 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

Ten fragment uratował mi dzień, ale potrzebowałem go, by objąć go relacjami, więc zmieniłem go, aby podzielić argument na "." i rekursywnie uzyskać wartość. Można to zrobić w jednym wierszu: return getattribute(getattribute(value,str(arg).split(".")[0]),".".join(str(arg).split(".")[1:])) , ale zostawiłem go na 4 dla czytelności. Mam nadzieję, że ktoś do tego użyje.

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) 
Powiązane problemy