Python django模板中的逗号分隔列表
如果Python django模板中的逗号分隔列表,python,django,list,django-templates,Python,Django,List,Django Templates,如果水果是列表[‘苹果’、‘橘子’、‘梨’] 有没有一种使用django模板标记快速生成“苹果、桔子和梨”的方法 我知道使用循环和{%if counter.last%}语句来实现这一点并不困难,但因为我将反复使用它,我想我将不得不学习如何编写自定义标记过滤器,如果已经完成了,我不想重新发明轮子 作为扩展,我尝试删除(即返回“apples、oranges和pears”)时更加混乱。第一选择:使用现有的join-template标记 这是他们的例子 {{ value|join:" // " }}
水果
是列表[‘苹果’、‘橘子’、‘梨’]
有没有一种使用django模板标记快速生成“苹果、桔子和梨”的方法
我知道使用循环和{%if counter.last%}
语句来实现这一点并不困难,但因为我将反复使用它,我想我将不得不学习如何编写自定义标记过滤器,如果已经完成了,我不想重新发明轮子
作为扩展,我尝试删除(即返回“apples、oranges和pears”)时更加混乱。第一选择:使用现有的join-template标记 这是他们的例子
{{ value|join:" // " }}
第二种选择:在视图中执行
fruits_text = ", ".join( fruits )
为模板提供
fruits\u text
以进行渲染。我建议使用自定义django模板过滤器,而不是自定义标记——过滤器更方便、更简单(在适当的情况下,如此处所示)<代码>{{fruits | joinby:“,”}看起来就像我想要的那样。。。使用自定义的joinby
过滤器:
def joinby(value, arg):
return arg.join(value)
正如你所看到的,这就是简单本身 这是我为解决问题而编写的过滤器(不包括牛津逗号)
def join_与_逗号(obj_列表):
“”“获取对象列表并返回其字符串表示形式,
用逗号分隔,倒数第二项和最后一项之间用“and”分隔
例如,对于水果对象列表:
[,]->“苹果、桔子和梨”
"""
如果不是obj_列表:
返回“”
l=len(对象列表)
如果l==1:
返回u“%s”%obj_列表[0]
其他:
返回“,”\
+“和”+str(obj_列表[l-1])
要在模板中使用它:
{{fruits | join_with_commas}
下面是一个超级简单的解决方案。将此代码放入comma.html:
{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}
现在,无论您将逗号放在何处,都应包含“comma.html”:
更新:@user3748764提供了一个稍微紧凑的版本,没有不推荐的ifequal语法:
{% if not forloop.first %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}
请注意,它应该在元素之前使用,而不是之后使用。如果您想在Michael Matthew Toomim的答案末尾使用“.”,请使用:
{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}{% if forloop.last %}.{% endif %}
Django没有现成的支持。您可以为此定义自定义筛选器:
from django import template
register = template.Library()
@register.filter
def join_and(value):
"""Given a list of strings, format them with commas and spaces, but
with 'and' at the end.
>>> join_and(['apples', 'oranges', 'pears'])
"apples, oranges, and pears"
"""
# convert numbers to strings
value = [str(item) for item in value]
if len(value) == 1:
return value[0]
# join all but the last element
all_but_last = ", ".join(value[:-1])
return "%s, and %s" % (all_but_last, value[-1])
但是,如果您想处理比字符串列表更复杂的内容,则必须在模板中使用显式的
{%for x in y%}
循环。如果您喜欢一行程序:
@register.filter
def lineup(ls): return ', '.join(ls[:-1])+' and '+ls[-1] if len(ls)>1 else ls[0]
然后在模板中:
{{ fruits|lineup }}
在Django模板上,这就是在每个水果后建立逗号所需做的全部工作。逗号到达最后一个水果后将停止
{% if not forloop.last %}, {% endif %}
在将其作为上下文数据发送到模板之前,我只需使用
,'.join(['apples','oranges','pears'])
更新:
data = ['apples', 'oranges', 'pears']
print(', '.join(data[0:-1]) + ' and ' + data[-1])
您将获得苹果、橙子和梨的输出。此处的所有答案都不符合以下一个或多个条件:
- 他们重写了标准模板库中的某些内容(很糟糕!)(确认,顶部答案!)
- 最后一项不使用
和
- 它们缺少一个连续的(牛津)逗号
- 它们使用负索引,这对django查询集不起作用
- 他们通常不会正确处理绳子卫生
class TestTextFilters(TestCase):
def test_oxford_zero_items(self):
self.assertEqual(oxford_comma([]), '')
def test_oxford_one_item(self):
self.assertEqual(oxford_comma(['a']), 'a')
def test_oxford_two_items(self):
self.assertEqual(oxford_comma(['a', 'b']), 'a and b')
def test_oxford_three_items(self):
self.assertEqual(oxford_comma(['a', 'b', 'c']), 'a, b, and c')
现在是代码。是的,它有点混乱,但您会看到它没有使用负索引:
from django.utils.encoding import force_text
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
@register.filter(is_safe=True, needs_autoescape=True)
def oxford_comma(l, autoescape=True):
"""Join together items in a list, separating them with commas or ', and'"""
l = map(force_text, l)
if autoescape:
l = map(conditional_escape, l)
num_items = len(l)
if num_items == 0:
s = ''
elif num_items == 1:
s = l[0]
elif num_items == 2:
s = l[0] + ' and ' + l[1]
elif num_items > 2:
for i, item in enumerate(l):
if i == 0:
# First item
s = item
elif i == (num_items - 1):
# Last item.
s += ', and ' + item
else:
# Items in the middle
s += ', ' + item
return mark_safe(s)
您可以在django模板中使用此选项:
{% load my_filters %}
{{ items|oxford_comma }}
我认为最简单的解决办法可能是:
@register.filter
定义逗号列表(p_值:Iterable[str])->list[str]:
值=列表(p_值)
如果len(值)>1:
值[-1]=u'和%s'%1]值[-1]
如果len(值)>2:
返回u','。连接(值)
返回u“”。连接(值)
我可能需要其他列表(例如蔬菜\u text
),我可能会在很多视图中使用这些列表,因此我宁愿有一个只需要修改模板的解决方案。我考虑编写自定义标记的原因之一是我可以使用Python-join
显然比循环更优雅。这也不会插入最后的“and”。在模板或视图中是否有这样做的最佳实践?我不知道标记和过滤器之间的区别。当我查看文档时,自定义标记似乎有点令人生畏,而过滤器似乎更简单,这正是我在本例中需要的。谢谢这不会插入最后的“and”。@Meekohi,因此返回arg.join(value[:-1])+”和“+value[-1]
(对于AP样式,即在和之前没有逗号;对于“Oxford逗号”样式,在“+”和“`”之前添加一个+arg
)。我,我更喜欢阿森顿的力量,佩尔。而且,关于英语风格的这场精彩辩论都不属于StackOverflow——请访问English.stackexchange.com!)+1用于返回6年前的问题以回答3年前的评论,但当数组中只有一项时,您的筛选器会做什么?:)使事物具有可读性似乎并不那么容易;插入和'
的新代码在上述注释中编码为无条件插入和'
。如果len(value)>1 else值
,那么在很短的时间内行为不同所需要的就是编码[[如上]并且顺便说一句,asyndeton是高度人类可读的——亚里士多德、莎士比亚、乔伊斯(当然还有许多其他人)所有人都有效地使用了它,我对它的偏爱首先是因为我是一名诗人。你为什么不使用现有的join template标记?@S.Lott:当我在文档页面上查看列表时,我没有发现join template标记。Oops。话虽如此,下一步是将列表中的每个项目包装在一个超链接中,我认为nk我需要写一个过滤器。如果你使用链接到你
from django.utils.encoding import force_text
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
@register.filter(is_safe=True, needs_autoescape=True)
def oxford_comma(l, autoescape=True):
"""Join together items in a list, separating them with commas or ', and'"""
l = map(force_text, l)
if autoescape:
l = map(conditional_escape, l)
num_items = len(l)
if num_items == 0:
s = ''
elif num_items == 1:
s = l[0]
elif num_items == 2:
s = l[0] + ' and ' + l[1]
elif num_items > 2:
for i, item in enumerate(l):
if i == 0:
# First item
s = item
elif i == (num_items - 1):
# Last item.
s += ', and ' + item
else:
# Items in the middle
s += ', ' + item
return mark_safe(s)
{% load my_filters %}
{{ items|oxford_comma }}