2009-04-07 24 views
22

Tôi tìm thấy một link để có thẻ 'chuyển' trong các mẫu Django, nhưng tôi đã tự hỏi liệu điều này có thể đạt được bằng cách nào đó mà không có nó. Chỉ sử dụng những thứ đi kèm với Django? Về cơ bản là có cách nào khác sau đó sử dụng nhiều 'if' hoặc 'ifequal' báo cáo?Làm cách nào để nhận chức năng báo cáo 'chuyển đổi' trong các mẫu Django?

Cảm ơn trước vì bất kỳ mẹo/đề xuất nào.

+0

+1 Cảm ơn cho liên kết, nhưng họ nói rằng mẫu không phải dành cho 'lập trình' và logic kinh doanh –

Trả lời

21

Thật không may, điều này là không thể với công cụ mẫu mặc định Django. Bạn sẽ phải viết một cái gì đó xấu xí như thế này để mô phỏng một công tắc.

{% if a %} 
    {{ a }} 
{% else %} 
    {% if b %} 
     {{ b }} 
    {% else %} 
     {% if c %} 
      {{ c }} 
     {% else %} 
      {{ default }} 
     {% endif %} 
    {% endif %} 
{% endif %} 

hoặc nếu chỉ một điều kiện có thể đúng và bạn không cần mặc định.

{% if a %} 
{{ a }} 
{% endif %} 
{% if b %} 
{{ b }} 
{% endif %} 
{% if c %} 
{{ c }} 
{% endif %} 

Thông thường, khi công cụ mẫu không đủ mạnh để thực hiện những gì bạn muốn, đây là dấu hiệu cho thấy mã sẽ được chuyển vào chế độ xem Django thay vì trong mẫu. Ví dụ:

# Django view 
if a: 
    val = a 
elif b: 
    val = b 
elif c: 
    val = c 
else: 
    val = default 

# Template 
{{ val }} 
+10

Kể từ Django 1.4, elif được hỗ trợ –

+1

Kiểm tra bộ lọc mẫu 'firstof', viết tắt này. Tôi không chắc khi nào nó được giới thiệu. – chris

2

Trong chế độ xem rất chung, cần phải tạo một lớp mới và đối tượng chụp các "trường hợp" khác nhau.

Sau đó, thay vì "swtich" ing khắp nơi, bạn chỉ cần gọi một phương thức đối tượng hoặc tham chiếu thuộc tính đối tượng và thực hiện.

+0

Làm cho tinh thần trong một ngôn ngữ OOP, nhưng không phải trong ngôn ngữ mẫu Django. Bạn không thể/không nên "gọi một phương thức đối tượng" để làm hiển thị trong mẫu Django. –

16

Đối với những người trả lời trước đây: Nếu không hiểu trường hợp sử dụng, bạn đã đưa ra các giả định và chỉ trích người hỏi. @Ber nói "tất cả các nơi" mà chắc chắn không được ngụ ý bởi người hỏi. Không đẹp.

Tôi có trường hợp tôi muốn thực hiện tuyên bố {% switch %} ở đúng một vị trí trong mẫu Django của tôi. Không chỉ thuận tiện để di chuyển tương đương với câu lệnh switch thành mã Python, mà thực sự làm cho cả khung nhìn và khuôn mẫu khó đọc và có logic điều kiện đơn giản nằm ở một nơi và chia nó thành hai nơi.

Trong nhiều trường hợp, tôi có thể tưởng tượng {% switch %} (hoặc {% if %}) hữu ích, không sử dụng yêu cầu đặt HTML ở chế độ xem. Đó là một tội lỗi tồi tệ hơn và là lý do tại sao {% if %} tồn tại ở nơi đầu tiên. {% switch %} không khác nhau.

May mắn thay, Django có thể mở rộng và nhiều người đã thực hiện chuyển đổi. Kiểm tra:

Switch template tag

from django import template 
from django.template import Library, Node, VariableDoesNotExist 

register = Library() 


@register.tag(name="switch") 
def do_switch(parser, token): 
    """ 
    The ``{% switch %}`` tag compares a variable against one or more values in 
    ``{% case %}`` tags, and outputs the contents of the matching block. An 
    optional ``{% else %}`` tag sets off the default output if no matches 
    could be found:: 

     {% switch result_count %} 
      {% case 0 %} 
       There are no search results. 
      {% case 1 %} 
       There is one search result. 
      {% else %} 
       Jackpot! Your search found {{ result_count }} results. 
     {% endswitch %} 

    Each ``{% case %}`` tag can take multiple values to compare the variable 
    against:: 

     {% switch username %} 
      {% case "Jim" "Bob" "Joe" %} 
       Me old mate {{ username }}! How ya doin? 
      {% else %} 
       Hello {{ username }} 
     {% endswitch %} 
    """ 
    bits = token.contents.split() 
    tag_name = bits[0] 
    if len(bits) != 2: 
     raise template.TemplateSyntaxError("'%s' tag requires one argument" % tag_name) 
    variable = parser.compile_filter(bits[1]) 

    class BlockTagList(object): 
     # This is a bit of a hack, as it embeds knowledge of the behaviour 
     # of Parser.parse() relating to the "parse_until" argument. 
     def __init__(self, *names): 
      self.names = set(names) 
     def __contains__(self, token_contents): 
      name = token_contents.split()[0] 
      return name in self.names 

    # Skip over everything before the first {% case %} tag 
    parser.parse(BlockTagList('case', 'endswitch')) 

    cases = [] 
    token = parser.next_token() 
    got_case = False 
    got_else = False 
    while token.contents != 'endswitch': 
     nodelist = parser.parse(BlockTagList('case', 'else', 'endswitch')) 

     if got_else: 
      raise template.TemplateSyntaxError("'else' must be last tag in '%s'." % tag_name) 

     contents = token.contents.split() 
     token_name, token_args = contents[0], contents[1:] 

     if token_name == 'case': 
      tests = map(parser.compile_filter, token_args) 
      case = (tests, nodelist) 
      got_case = True 
     else: 
      # The {% else %} tag 
      case = (None, nodelist) 
      got_else = True 
     cases.append(case) 
     token = parser.next_token() 

    if not got_case: 
     raise template.TemplateSyntaxError("'%s' must have at least one 'case'." % tag_name) 

    return SwitchNode(variable, cases) 

class SwitchNode(Node): 
    def __init__(self, variable, cases): 
     self.variable = variable 
     self.cases = cases 

    def __repr__(self): 
     return "<Switch node>" 

    def __iter__(self): 
     for tests, nodelist in self.cases: 
      for node in nodelist: 
       yield node 

    def get_nodes_by_type(self, nodetype): 
     nodes = [] 
     if isinstance(self, nodetype): 
      nodes.append(self) 
     for tests, nodelist in self.cases: 
      nodes.extend(nodelist.get_nodes_by_type(nodetype)) 
     return nodes 

    def render(self, context): 
     try: 
      value_missing = False 
      value = self.variable.resolve(context, True) 
     except VariableDoesNotExist: 
      no_value = True 
      value_missing = None 

     for tests, nodelist in self.cases: 
      if tests is None: 
       return nodelist.render(context) 
      elif not value_missing: 
       for test in tests: 
        test_value = test.resolve(context, True) 
        if value == test_value: 
         return nodelist.render(context) 
     else: 
      return "" 
+0

Điều này thật tuyệt vời! Tôi nghĩ rằng bổ sung duy nhất của tôi sẽ là để làm cho nó, do đó bạn có thể chỉ định một 'với x là y' và có nó vượt qua y xuống mỗi trường hợp. Nhưng đó là một yêu cầu thích hợp. – Pureferret

41

Tính đến Django 1.4, có {% elif %}:

{% if a %} 
    thing 
{% elif b %} 
    other thing 
{% elif c %} 
    another thing 
{% endif %} 
+2

Khi kết hợp với thẻ 'với', chúng tôi có thể nhận được khá dang gần một công tắc. '{% with a = ya.expensive.bro%} {% if a = 1%} một {% elif a = 2%} hai {% else%} uhh {% endif%} {% endwith%}' .. Nó chỉ là một cái chạm xấu xí. –

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