2009-08-06 56 views
54

Nếu fruits là danh sách ['apples', 'oranges', 'pears'],Comma tách danh sách trong django mẫu

là có một cách nhanh chóng sử dụng mẫu thẻ django để sản xuất "táo, cam, lê và"?

Tôi biết không khó để làm điều này bằng cách sử dụng vòng lặp và câu lệnh {% if counter.last %}, nhưng vì tôi sẽ sử dụng liên tục này, tôi nghĩ mình sẽ phải học cách viết các bộ lọc tùy chỉnh không muốn phát minh lại bánh xe nếu nó đã được thực hiện.

Là tiện ích mở rộng, nỗ lực của tôi để xóa số Oxford Comma (nghĩa là trả lại "táo, cam và lê") thậm chí còn lộn xộn hơn.

+2

Tại sao bạn không sử dụng thẻ mẫu tham gia hiện tại? –

+1

@ S.Lott: Tôi không phát hiện thẻ mẫu tham gia khi tôi xem qua danh sách trên trang tài liệu. Rất tiếc. Có nói rằng, giai đoạn tiếp theo là để bọc mỗi mục trong danh sách trong một siêu liên kết, mà tôi nghĩ rằng tôi sẽ cần phải viết một bộ lọc. – Alasdair

+0

Nếu bạn đang sử dụng liên kết đến URL Django của bạn, bạn sẽ cần phải sử dụng thẻ '{% url%}'. Vòng lặp '{% for%}' đột nhiên trông hấp dẫn hơn nhiều. "Lặp lại" thường có nghĩa là các mẫu của bạn cần '{% include%}' các tính năng phổ biến. –

Trả lời

30

Tôi sẽ đề xuất một bộ lọc tùy chỉnh django thay vì thẻ tùy chỉnh - bộ lọc dễ sử dụng hơn và đơn giản hơn (nếu thích hợp, như ở đây). {{ fruits | joinby:", " }} trông giống như những gì tôi muốn có cho mục đích ... với một tùy chỉnh joinby lọc:

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

mà như bạn thấy là sự đơn giản chính nó!

+0

Tôi không biết sự khác biệt giữa thẻ và bộ lọc. Trong khi các thẻ tùy chỉnh có vẻ hơi khó khăn khi tôi xem tài liệu, các bộ lọc dường như đơn giản hơn và chính xác những gì tôi cần trong trường hợp này. Cảm ơn! – Alasdair

+5

Điều này không chèn cuối cùng "và". – Meekohi

+1

@Meekohi, do đó 'trả về arg.join (giá trị [: - 1]) + 'và' + giá trị [-1]' (đối với kiểu AP, nghĩa là không có dấu phẩy trước 'và'; cho kiểu" dấu phẩy Oxford ", thêm một '+ arg' ngay trước dấu '+' và''). Tôi, tôi thích sức mạnh của asyndeton, theo http://literarydevices.net/asyndeton/. Và không ai trong số các cuộc tranh luận tốt về phong cách tiếng Anh thuộc về StackOverflow anyway - mang nó đến english.stackexchange.com! -) –

111

Lựa chọn đầu tiên: sử dụng thẻ mẫu tham gia hiện có.

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

Dưới đây là ví dụ của họ

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

sự lựa chọn thứ hai: làm điều đó trong giao diện.

fruits_text = ", ".join(fruits) 

Cung cấp fruits_text cho mẫu để hiển thị.

+0

Tôi có thể yêu cầu các danh sách khác (ví dụ: 'vegetables_text') và tôi có thể sử dụng các danh sách này trong nhiều lượt xem, vì vậy tôi muốn có giải pháp chỉ yêu cầu tôi thay đổi các mẫu. Một trong những lý do tôi nghĩ đến việc viết một thẻ tùy chỉnh là tôi có thể sử dụng Python - 'join' chắc chắn là thanh lịch hơn cho các vòng lặp. – Alasdair

+4

Điều này cũng không chèn "cuối cùng" và "cuối cùng". – Meekohi

+0

Có cách nào tốt nhất để thực hiện điều này trong mẫu hoặc trong chế độ xem không? – Rikki

6

Dưới đây là bộ lọc tôi đã viết để giải quyết vấn đề của tôi:

def join_with_commas(obj_list): 
    """Takes a list of objects and returns their unicode representations, 
    seperated 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(unicode(obj) for obj in obj_list[:l-1]) \ 
       + " and " + unicode(obj_list[l-1]) 

Để sử dụng nó trong các mẫu: {{ fruits | join_with_commas }}

59

Dưới đây là một giải pháp siêu đơn giản. Đặt mã này vào comma.html:

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

Và bây giờ bất cứ nơi nào bạn muốn đặt dấu phẩy, bao gồm "comma.html" thay vì: ''

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

Rất hữu ích. Cảm ơn! –

+3

giải pháp tốt nhất nếu bạn cần tham gia nhiều hơn các chuỗi trong một mảng – BiAiB

+0

Giải pháp rất thông minh. – vmassuchetto

4

Nếu bạn muốn có một vào cuối câu trả lời của Michael Matthew Toomim, sau đó sử dụng:

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

Django không có hỗ trợ cho cái hộp này. Bạn có thể xác định một bộ lọc tùy chỉnh cho việc này:

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

Tuy nhiên, nếu bạn muốn để đối phó với một cái gì đó phức tạp hơn là chỉ danh sách các chuỗi, bạn sẽ phải sử dụng một vòng lặp {% for x in y %} rõ ràng trong mẫu của bạn.

0

Nếu bạn thích một lớp lót:

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

và sau đó trong mẫu:

{{ fruits|lineup }} 
13

Trên mẫu Django tất cả điều này bạn cần làm cho việc thiết lập một dấu phẩy sau mỗi trái cây. Dấu phẩy sẽ dừng lại khi nó đạt đến quả cuối cùng.

{% if not forloop.last %}, {% endif %} 
+1

Giải pháp rất sạch sẽ và dễ dàng. – SaeX

Các vấn đề liên quan