web-dev-qa-db-ja.com

Djangoテンプレートのコンマ区切りリスト

fruitsがリスト['apples', 'oranges', 'pears']の場合、

Djangoテンプレートタグを使用して「リンゴ、オレンジ、ナシ」を作成する簡単な方法はありますか?

ループと{% if counter.last %}ステートメントを使用してこれを行うことは難しいことではないことを知っていますが、これを繰り返し使用するため、カスタムの書き方を学ぶ必要があると思います タグ フィルターを使用します。ホイールが既に作成されている場合は、ホイールを再発明したくありません。

拡張機能として、 Oxford Comma (つまり、「リンゴ、オレンジ、梨」を返す)をドロップしようとする試みは、さらに厄介です。

65
Alasdair

これが私の問題を解決するために書いたフィルターです(オックスフォードコンマは含まれていません)

def join_with_commas(obj_list):
    """Takes a list of objects and returns their string representations,
    separated by commas and with 'and' between the penultimate and final items
    For example, for a list of fruit objects:
    [<Fruit: apples>, <Fruit: oranges>, <Fruit: pears>] -> 'apples, oranges and pears'
    """
    if not obj_list:
        return ""
    l=len(obj_list)
    if l==1:
        return u"%s" % obj_list[0]
    else:    
        return ", ".join(str(obj) for obj in obj_list[:l-1]) \
                + " and " + str(obj_list[l-1])

テンプレートで使用するには:{{ fruits|join_with_commas }}

8
Alasdair

最初の選択:既存の結合テンプレートタグを使用します。

http://docs.djangoproject.com/en/dev/ref/templates/builtins/#join

ここに彼らの例があります

{{ value|join:" // " }}

2番目の選択:ビューで実行します。

fruits_text = ", ".join( fruits )

fruits_textレンダリング用のテンプレートに。

128
S.Lott

これは非常にシンプルなソリューションです。このコードをcomma.htmlに入れてください:

{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}

そして今、あなたがコンマを置くどこにでも、代わりに "comma.html"を含めてください:

{% for cat in cats %}
Kitty {{cat.name}}{% include "comma.html" %}
{% endfor %}

カスタムtagではなく、カスタムDjango templatingfilter)をお勧めします-フィルタは便利でシンプル(適切な場合、ここのように){{ fruits | joinby:", " }}は、目的のために欲しいもののように見えます...カスタムjoinbyフィルターで:

def joinby(value, arg):
    return arg.join(value)

あなたが見るように、それはシンプルそのものです!

34
Alex Martelli

Djangoテンプレートで、これは各果物の後にコンマを確立するために必要なことです。コンマは最後の果物に到達すると停止します。

{% if not forloop.last %}, {% endif %}
24
Tommygun

「。」が必要な場合Michael Matthew Toomimの答えの最後に、次を使用します。

{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}{% if forloop.last %}.{% endif %}
4
Todd Davies

ここでの答えはすべて、次の1つ以上に失敗します。

  • 彼らは標準テンプレートライブラリにある何かを書き直します(悪い!)(ack、top answer!)
  • 最後のアイテムにandを使用しません。
  • シリアル(オックスフォード)コンマがありません。
  • これらは、Django querysetsでは機能しないネガティブインデックスを使用します。
  • 彼らは通常、文字列の衛生を適切に処理しません。

このキヤノンへの私のエントリーです。最初に、テスト:

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

そして今、コード。はい、少し面倒になりますが、あなたはそれを見ることができますdoes n't負のインデックスを使用します:

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

コンテキストデータとしてテンプレートに送信する前に、単に', '.join(['apples', 'oranges', 'pears'])を使用します。

更新:

data = ['apples', 'oranges', 'pears']
print(', '.join(data[0:-1]) + ' and ' + data[-1])

apples, oranges and pears出力。

1
Yiğit Genç

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 %}ループを使用する必要があります。

1
Wilfred Hughes

ワンライナーが好きな場合:

@register.filter
def lineup(ls): return ', '.join(ls[:-1])+' and '+ls[-1] if len(ls)>1 else ls[0]

そしてテンプレートで:

{{ fruits|lineup }}
0
F. Malina