Django 模板: 选择的详细版本

我有一个模型:

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.view。默认模板打印选项的简短版本(‘ e’而不是‘ Fabulousegg’) ,因为它使用

{% 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 中已经可用了吗?

75520 次浏览

我不认为有什么内置的方法可以做到这一点。不过,一个过滤器或许可以起到这样的作用:

@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 %}

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

注意: 如果标准的 FormPreview模板没有使用它,那么您总是可以为该表单使用 提供您自己的模板,它将包含类似于 \{\{ form.get_meal_display }}的内容。

基于诺亚的回答,这里有一个版本对没有选择的领域免疫:

#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

我不确定为此目的使用过滤器是否合适。如果有人有更好的解决办法,我会很高兴看到:)谢谢你,诺亚!

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

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

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

 \{\{ x.get_choices_display }}

这里,x 是模型实例。 希望能有帮助。

添加一个简单的函数:

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”是否足够,但它是有效的。 :)

我很抱歉,如果这个答案是多余的任何列出以上,但似乎这一个尚未提供,它似乎相当干净。我是这样解决这个问题的:

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 }}

在 Model.get _ FOO _ display ()中,FOO 是具有选项的字段的名称。

在你的模板中这样做:

\{\{ scoop.get_flavor_display }}

诺亚解决方案和伊万解决方案的扩展版本。还修复了诺亚解决方案的姜戈3.1,因为 ModelChoiceIteratorValue现在是不可散列的。

@register.filter
def display_value(value: Any, arg: str = None) -> str:
"""Returns the display value of a BoundField or other form fields"""
if not arg:  # attempt to auto-parse
# Returning regular field's value
if not hasattr(value.field, 'choices'): return value.value()
# Display select value for BoundField / Multiselect field
# This is used to get_..._display() for a read-only form-field
# which is not rendered as Input, but instead as text
return list(value.field.choices)[value.value()][1]


# usage: \{\{ field|display_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)()
return getattr(value, arg)


return value.get(arg) or ''
<select class="form-select">
{% for key, value in form.meal.field.choices %}
{% if form.meal.value == key %}
<option value="\{\{ form.key }}" selected>\{\{ value }}</option>
{% else %}
<option value="\{\{ key }}">\{\{ value }}</option>
{% endif %}
{% endfor %}
</select>

那边怎么样?

在模特界,是的

class MealOrder(models.Model):
CHOICES = (
('s', 'Glorious spam'),
('e', 'Fabulous eggs'),
)
meal = models.CharField(max_length=8, choices=CHOICES)
meal_value = models.CharField(max_length=1, blank=True, null=True,
editable=False)
    

def save(self, *args, **kwargs):
if self.meal == "s":
self.meal_value = "Glorious spam"
elif self.meal == "e":
self.meal_value = "Fabulous eggs"
super(MealOrder, self).save(*args, **kwargs)

在视野里

from .models import MealOrder


def meal_order(request):
meals = MealOrder.objects.all()


return render(request, "meals.html", {
"meals": meals,
})

在 meals.html 中

{% for meal in meals %}
\{\{meal.meal_value }}
{%endfor%}