Django模板:选择的详细版本


127

我有一个模型:

from django.db import models

CHOICES = (
    ('s', 'Glorious spam'),
    ('e', 'Fabulous eggs'),
)

class MealOrder(models.Model):
    meal = models.CharField(max_length=8, choices=CHOICES)

我有一个表格:

from django.forms import ModelForm

class MealOrderForm(ModelForm):
    class Meta:
        model = MealOrder

我想使用formtools.preview。默认模板会打印所选内容的简短版本(“ e”而不是“ Fabricous eggs”),因为它使用了

{% for field in form %}
<tr>
<th>{{ field.label }}:</th>
<td>{{ field.data }}</td>
</tr>
{% endfor %}.

我想要一个如上所述的通用模板,但是要打印“精美的鸡蛋”。

[因为我怀疑真正的问题在哪里,所以我为我们所有人加粗了它:)]

我知道如何以一种丑陋的方式获取选项的详细版本:

{{ form.meal.field.choices.1.1 }}

真正的痛苦是我需要获得选择的选择,而我想到的唯一方法是遍历选择和检查{% ifequals currentChoice.0 choiceField.data %},这更加丑陋。

能容易做到吗?还是需要一些模板标签编程?那不是应该已经在django中可用了吗?

Answers:


258

在Django模板中,您可以使用“ get_FOO_display()”方法,该方法将返回该字段的可读别名,其中'FOO'是该字段的名称。

注意:如果标准FormPreview模板未使用它,那么您始终可以为该表单提供自己的模板,其中将包含{{ form.get_meal_display }}


1
是的我知道。但是,它并不那么普遍(通用)-除非您知道在模型对象的所有get_FOO_display方法上迭代模板的方法:)对于编写非通用模板,我有点懒惰;)此外,文档还说这是模型实例的方法。因此,它必须是绑定到现有对象的模型形式,这不是事实,也不是一般性的。
2009年

2
请注意,这种用法不仅限于视图,get_FOO_display()是模型对象本身的方法,因此您也可以在模型代码中使用它!例如,在__unicode __()中,它非常方便
Bogatyr 2014年

51

解决您的问题的最佳方法是使用辅助函数。如果选项存储在变量CHOICES中,并且存储所选选项的模型字段为' choices ',则可以直接使用

 {{ x.get_choices_display }}

在您的模板中。在此,x是模型实例。希望能帮助到你。


3
在已经找到有用的答案的两年后,为什么还要这样回答?谁来投票呢?其相同的答案@roberto短短2年后....
boatcoder

15
@ Mark0978赞成此答案的原因是因为(对我而言)遵循“最高投票”答案更为明确。YMMV。
Nir Levy

49

抱歉,如果上述答案与上面列出的任何答案都是多余的,但似乎尚未提供此答案,而且看起来还算干净。这是我解决此问题的方法:

from django.db import models

class Scoop(models.Model):
    FLAVOR_CHOICES = [
        ('c', 'Chocolate'),
        ('v', 'Vanilla'),
    ]

    flavor = models.CharField(choices=FLAVOR_CHOICES)

    def flavor_verbose(self):
        return dict(Scoop.FLAVOR_CHOCIES)[self.flavor]

我的视图将Scoop传递给模板(注意:不是 Scoop.values()),并且该模板包含:

{{ scoop.flavor_verbose }}

10

根据Noah的回复,这是不受字段选择影响的版本:

#annoyances/templatetags/data_verbose.py
from django import template

register = template.Library()

@register.filter
def data_verbose(boundField):
    """
    Returns field's data or it's verbose version 
    for a field with choices defined.

    Usage::

        {% load data_verbose %}
        {{form.some_field|data_verbose}}
    """
    data = boundField.data
    field = boundField.field
    return hasattr(field, 'choices') and dict(field.choices).get(data,'') or data

我不确定是否可以为此目的使用过滤器。如果有人有更好的解决方案,我将很高兴看到它:)谢谢,诺亚!


+1表示您的路径#annoyances / templatetags / ...大声笑...我使用get_FOO_display(),该信息在表单文档的底部提到。
fmalina 2011年

在选项上使用hasattr的好主意!
奥登2014年

7

我们可以通过Noah扩展过滤器解决方案, 使其在处理数据和字段类型时更加通用:

<table>
{% for item in query %}
    <tr>
        {% for field in fields %}
            <td>{{item|human_readable:field}}</td>
        {% endfor %}
    </tr>
{% endfor %}
</table>

这是代码:

#app_name/templatetags/custom_tags.py
def human_readable(value, arg):
    if hasattr(value, 'get_' + str(arg) + '_display'):
        return getattr(value, 'get_%s_display' % arg)()
    elif hasattr(value, str(arg)):
        if callable(getattr(value, str(arg))):
            return getattr(value, arg)()
        else:
            return getattr(value, arg)
   else:
       try:
           return value[arg]
       except KeyError:
           return settings.TEMPLATE_STRING_IF_INVALID
register.filter('human_readable', human_readable)

似乎相当普遍:)不能肯定地说,因为自那时以来我没有做太多的Python或Django。可惜的是,它仍然需要一个第三方(Django中未包含)过滤器(否则您会告诉我们,伊万,不是吗?;))……
Artur Gajowy

@ArturGajowy是的,到目前为止,Django中没有此类默认功能。我已经提出了,谁知道呢,也许会被批准
伊万·哈拉莫夫

完善!奇迹般有效!自定义模板过滤器ROX!谢谢!:-)
CeDeROM

5

我认为没有任何内置方法可以做到这一点。不过,过滤器可能会解决问题:

@register.filter(name='display')
def display_value(bf):
    """Returns the display value of a BoundField"""
    return dict(bf.field.choices).get(bf.data, '')

然后,您可以执行以下操作:

{% for field in form %}
    <tr>
        <th>{{ field.label }}:</th>
        <td>{{ field.data|display }}</td>
    </tr>
{% endfor %}

3

添加到您的models.py一个简单的功能:

def get_display(key, list):
    d = dict(list)
    if key in d:
        return d[key]
    return None

现在,您可以像这样获得选择字段的详细值:

class MealOrder(models.Model):
    meal = models.CharField(max_length=8, choices=CHOICES)

    def meal_verbose(self):
        return get_display(self.meal, CHOICES)    

更新:我不确定,该解决方案是否足够“ pythonic”和“ django-way”,但它可以工作。:)


0

您具有Model.get_FOO_display(),其中FOO是具有选择项的字段的名称。

在您的模板中执行以下操作:

{{ scoop.get_flavor_display }}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.