Question

La méthode getattr () de Python est utile lorsque vous ne connaissez pas à l'avance le nom d'un certain attribut.

Cette fonctionnalité serait également utile dans les modèles, mais je n’ai jamais trouvé le moyen de le faire. Existe-t-il une balise intégrée ou une balise non intégrée pouvant effectuer des recherches d'attributs dynamiques?

Était-ce utile?

La solution

J'ai également dû écrire ce code récemment en tant que balise de modèle personnalisé. Pour gérer tous les scénarios de recherche, il effectue d'abord une recherche d'attribut standard, puis essaie de faire une recherche avec un dictionnaire, puis tente une recherche getitem (pour que les listes fonctionnent), puis se conforme à la norme. Le comportement du template Django quand un objet est introuvable.

(mis à jour le 26/08/2009 pour gérer désormais les recherches dans l'index des listes)

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

Utilisation du modèle:

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


Autres conseils

Je ne pense pas. Mais il ne serait pas trop difficile d’écrire une balise de modèle personnalisé pour retourner un attribut dans le contexte dict. Si vous essayez simplement de renvoyer une chaîne, essayez quelque chose comme ceci:

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)

Notez qu'il est probablement aussi facile de le faire dans votre vue que dans le modèle, à moins qu'il ne s'agisse d'une condition qui se répète souvent dans vos données.

J'ai fini par ajouter une méthode au modèle en question, et cette méthode est accessible comme un attribut dans le modèle.

Néanmoins, je pense que ce serait bien si une balise intégrée vous permettait de rechercher dynamiquement un attribut, car c’est un problème que beaucoup d’entre nous ont constamment dans nos modèles.

Garder la distinction entre get et 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

Il n'y a pas de balise intégrée, mais il ne devrait pas être trop difficile de écrivez votre propre .

Cet extrait m'a sauvé la journée, mais j'avais besoin de l'étaler sur les relations et je l'ai donc modifié pour diviser l'argument par & ";. &"; et récursivement obtenir la valeur. Cela pourrait être fait en une seule ligne: return getattribute(getattribute(value,str(arg).split(".")[0]),".".join(str(arg).split(".")[1:])) mais je l'ai laissé en 4 pour plus de lisibilité. J'espère que quelqu'un a utilisé pour cela.

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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top