【问题标题】:Django template how to look up a dictionary value with a variableDjango模板如何使用变量查找字典值
【发布时间】:2011-12-21 10:48:40
【问题描述】:
mydict = {"key1":"value1", "key2":"value2"}

在 Django 模板中查找字典值的常规方法是 {{ mydict.key1 }}{{ mydict.key2 }}。如果键是循环变量怎么办?即:

{% for item in list %} # where item has an attribute NAME
  {{ mydict.item.NAME }} # I want to look up mydict[item.NAME]
{% endfor %}

mydict.item.NAME 失败。如何解决这个问题?

【问题讨论】:

    标签: python django templates dictionary


    【解决方案1】:

    写一个custom template filter

    from django.template.defaulttags import register
    ...
    @register.filter
    def get_item(dictionary, key):
        return dictionary.get(key)
    

    (我使用.get,因此如果密钥不存在,则返回无。如果您使用dictionary[key],则会引发KeyError。)

    用法:

    {{ mydict|get_item:item.NAME }}
    

    【讨论】:

    【解决方案2】:

    在循环中从字典中获取键和值:

    {% for key, value in mydict.items %}
        {{ value }}
    {% endfor %}
    

    我发现这更容易阅读,并且无需特殊编码。无论如何,我通常需要循环内的键和值。

    【讨论】:

    • 他没有要求枚举字典(如您所示) - 他要求在给定变量键的情况下获取字典的值。您的提案没有提供解决方案。
    • 这是一个解决方案(只是非常低效),因为您可以枚举 dict 的项目,然后与列表中的键匹配。
    • 请注意,如果您尝试访问的字典中包含另一个字典,则此方法不起作用。
    • 如果您的值是 dicts,您可以包含另一个 for 循环来处理它们的键和值,但很可能复杂性使您倾向于使用 @culebron 的答案中描述的自定义过滤器。
    【解决方案3】:

    默认情况下你不能。点是属性查找/键查找/切片的分隔符/触发器。

    点在模板渲染中具有特殊的含义。变量中的点 name 表示查找。具体来说,当模板系统 在变量名中遇到一个点,它会尝试以下查找, 按此顺序:

    • 字典查找。示例:foo["bar"]
    • 属性查找。示例:foo.bar
    • 列表索引查找。示例:foo[bar]

    但你可以制作一个过滤器,让你传入一个参数:

    https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-filters

    @register.filter(name='lookup')
    def lookup(value, arg):
        return value[arg]
    
    {{ mydict|lookup:item.name }}
    

    【讨论】:

    • 我仍然会使用return value.get(arg),因为如果密钥不存在,它不会抛出 KeyError 异常。
    • 返回值.get(arg, None)
    【解决方案4】:

    对我来说,在我的应用程序中创建一个名为 template_filters.py 的 python 文件,内容如下

    # coding=utf-8
    from django.template.base import Library
    
    register = Library()
    
    
    @register.filter
    def get_item(dictionary, key):
        return dictionary.get(key)
    

    用法就像 culebrón 所说的:

    {{ mydict|get_item:item.NAME }}
    

    【讨论】:

    • 为什么是register = Library()?它有什么作用?
    • 如果你想让你的所有模板都知道你的新过滤器,那么你必须在django.template.base.Library类下注册它。通过register = Library(),我们实例化该类并在其中使用filter 函数注释器来满足我们的需求。
    【解决方案5】:

    我也遇到过类似的情况。但是我使用了不同的解决方案。

    在我的模型中,我创建了一个进行字典查找的属性。然后在模板中使用该属性。

    在我的模型中:-

    @property
    def state_(self):
        """ Return the text of the state rather than an integer """
        return self.STATE[self.state]
    

    在我的模板中:-

    The state is: {{ item.state_ }}
    

    【讨论】:

      【解决方案6】:

      环境:Django 2.2

      1. 示例代码:
      
      
          from django.template.defaulttags import register
      
          @register.filter(name='lookup')
          def lookup(value, arg):
              return value.get(arg)
      
      

      我将此代码放在我的项目文件夹中的一个名为 template_filters.py 的文件中,该文件名为portfoliomgr

      1. 无论您将过滤器代码放在何处,请确保该文件夹中有 __init__.py

      2. 将该文件添加到 projectfolder/settings.py 文件中模板部分的库部分。对我来说,它是portfoliomgr/settings.py

      
      
          TEMPLATES = [
              {
                  'BACKEND': 'django.template.backends.django.DjangoTemplates',
                  'DIRS': [os.path.join(BASE_DIR, 'templates')],
                  'APP_DIRS': True,
                  'OPTIONS': {
                      'context_processors': [
                          'django.template.context_processors.debug',
                          'django.template.context_processors.request',
                          'django.contrib.auth.context_processors.auth',
                          'django.contrib.messages.context_processors.messages',
                      ],
                      'libraries':{
                          'template_filters': 'portfoliomgr.template_filters',
                      }
                  },
              },
          ]
      
      
      1. 在您的 html 代码中加载库

        
        {% load template_filters %}
        

      【讨论】:

        【解决方案7】:

        由于无法发表评论,让我以答案的形式进行:
        culebrón's answerYuji 'Tomita' Tomita's answer 为基础,传入函数的字典是以字符串的形式,所以可能先使用ast.literal_eval 将字符串转换为字典,就像this example 一样。

        通过此编辑,代码应如下所示:

        # code for custom template tag
        @register.filter(name='lookup')
        def lookup(value, arg):
            value_dict = ast.literal_eval(value)
            return value_dict.get(arg)
        
        <!--template tag (in the template)-->
        {{ mydict|lookup:item.name }}
        

        【讨论】:

        • 是否可以将返回的值({{ mydict|lookup:item.name }})赋给变量
        • @Jibin 我不确定你的问题是什么意思。也许我的代码令人困惑;从那时起,我已对其进行了更正并添加了 cmets。
        • @Jibin 来自 grails/gsp 和其他模板语言 我有同样的问题 - 但在 django 中需要考虑不同:您可以在渲染模板之前 这样做.当您在视图中为模板创建上下文时,您只需将瞬态属性和(我相信)甚至方法添加到您的模型对象并从模板中访问它们 - 非常适合您在该模板中需要的所有临时内容,并且非常易读模板代码。
        【解决方案8】:

        环境:django 2.1.7

        查看:

        dict_objs[query_obj.id] = {'obj': query_obj, 'tag': str_tag}
        return render(request, 'obj.html', {'dict_objs': dict_objs})
        

        模板:

        {% for obj_id,dict_obj in dict_objs.items %}
        <td>{{ dict_obj.obj.obj_name }}</td>
        <td style="display:none">{{ obj_id }}</td>
        <td>{{ forloop.counter }}</td>
        <td>{{ dict_obj.obj.update_timestamp|date:"Y-m-d H:i:s"}}</td>
        

        【讨论】:

        • 模板代码{{ dict_obj.obj.obj_name }}在这种情况下等同于Python代码dict_obj["obj"]["obj_name"],但是,问题大约相当于dict_obj[obj][obj_name]
        • 如何在模板中使用答案?
        猜你喜欢
        • 2014-02-01
        • 1970-01-01
        • 2017-11-07
        • 1970-01-01
        相关资源
        最近更新 更多