Django 模板:使用 get_FOO_display() 强制选择字段并打印显示值

Posted

技术标签:

【中文标题】Django 模板:使用 get_FOO_display() 强制选择字段并打印显示值【英文标题】:Django template: force choices on field and print display value with get_FOO_display() 【发布时间】:2018-08-12 00:15:45 【问题描述】:

我想要一个有 5 个选项的模型,但我不能强制它们并在模板中显示显示值。我使用 CharField(choice=..) 代替 docs 中的 ChoiceField 或 TypeChoiceField。我尝试了here 的解决方案,但它们对我不起作用(见下文)。

模型.py:

class Language(models.Model):
    language = models.CharField(max_length=20,blank=False)
    ILR_scale = (
        (5, 'Native'),
        (4, 'Full professional proficiency'),
        (3, 'Professional working proficiency'),
        (2, 'Limited professional proficiency'),
        (1, 'Elementary professional proficiency')
        )
    level = models.CharField(help_text='Choice between 1 and 5', default=5, max_length=25, choices=ILR_scale)
    def level_verbose(self):
        return dict(Language.ILR_scale)[self.level]
    class Meta:
        ordering = ['level','id']
    def __unicode__(self):
        return ''.join([self.language, '-', self.level])

view.py

..
def index(request):
language = Language.objects.all()
..

我的模板.html

<div class="subheading strong-underlined mb-3 my-3">
      Languages
      </div>
      % regroup language|dictsortreversed:"level" by level as level_list %
      <ul>
        % for lan_list in level_list %
        <li>
          % for lan in lan_list.list %
          <strong> lan.language </strong>:  lan.level_verbose %if not forloop.last%,%endif%
          % endfor %
        </li>
        % endfor %
      </ul>

从外壳:

python3 manage.py shell
from resume.models import Language
l1=Language.objects.create(language='English',level=4)
l1.save()
l1.get_level_display()   #This is good
Out[20]: 'Full professional proficiency'

一旦我从 shell 创建了 Language 实例,我就无法加载该站点。它在模板的第 0 行失败,异常类型:KeyError,异常值:'4',异常位置:level_verbose 中的 /models.py 第 175 行(这是 level_verbose 方法的返回行)。

另外,我预计 shell 会出现验证错误:

l1.level='asdasd'
l1.save()     #Why can I save this instance with this level?

而且我还可以在使用 ChoiceField 时保存上面显示的内容,这意味着我不明白该字段的用途。

如何强制实例在选择中获取字段值,并在模板中显示显示值?

【问题讨论】:

它在字典中寻找字符串 '4' 而不是 4。试试 。 - return dict(Language.ILR_scale)[int(self.leve)] 您正在混淆字符串和整数。如果您想使用整数键,您可能应该使用IntegerField 而不是CharField。这将确保在保存之前将值正确转换为整数。 是的,解决了它。我认为 ChoiceField 是用于表单,而不是用于模型 【参考方案1】:

这也是我开始使用 django 时的常见问题。所以首先让我们看看 django 的特性,你可以像下面那样做(注意:你选择的情况的值将被存储为整数,所以你应该使用 models.IntegerField 而不是 models.CharField):

get_FOO_display():你非常接近这个解决方案。

正如您在文档中看到的那样,FOO 是模型的字段名称。在您的情况下,它是level,因此当您想在 shell 或视图中访问相应的选择值时,您可以使用模型实例调用方法,如下所示:

`l1.get_level_display()`

但是当你想在模板文件中访问它时,你需要像下面这样写:

 l1.get_level_display 
现在让我们看看你的方法level_verbose(),如果你再次看到你的模型是一个类并且level_verbose()是你创建的方法,你可以直接访问self.ILR_scale,就像你使用self.level一样

您创建 ILR_scale 字典的主要问题是它的键是整数值 (i.e. 1, 2, 3, 4, 5) 但您已使用 CharField() 来存储返回字符串值 (i.e. '1', '2', '3', '4' or '5') 和 python 字典键 1 和 '1' 的级别值两者都不同,一个是整数,另一个是字符串。因此,您可以将模型字段更改为 models.IntegerField() 或者您可以访问诸如

之类的键
dict(self.ILR_scal)[int(self.level)]

【讨论】:

当然!整数字段有效。我仍然觉得奇怪的是我可以保存 l1.level=555,但随后网站崩溃了。出于这个原因,我认为使用验证器会更安全。现在让我试试 get_FOO_display.. 您正在使用选择在模型中存储值,这意味着当您在模板中运行程序时,django 正在验证您的结果;如果您以这种方式静态分配,它将无法正确处理任何异常。 是的, lan.get_level_display 也可以。由于错误的 CharField,它对我不起作用。谢谢【参考方案2】:

您也可以使用models.CharField,但您必须为您的元组设置字段选项choices

例如:

FRESHMAN = 'FR'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'
LEVELS = (
    (FRESHMAN, 'Freshman'),
    (SOPHOMORE, 'Sophomore'),
    (JUNIOR, 'Junior'),
    (SENIOR, 'Senior'),
)
level = models.CharField(
    max_length=2,
    choices=LEVELS,
    default=FRESHMAN,
)

然后在您的模板中,您可以使用get_FOO_display(),例如: l1.get_level_display

在docs中查看更多信息

【讨论】:

以上是关于Django 模板:使用 get_FOO_display() 强制选择字段并打印显示值的主要内容,如果未能解决你的问题,请参考以下文章

Jinja2 模板使用 Django 模板标签

Django的模板系统

django模板继承使用相同标签多个模板

django-模板

使用 Django 的模板引擎而不使用 Django 的其余部分

[Django学习]模板