วิธีการตั้งค่าของตัวแปรภายในรหัสแม่แบบ?


216

บอกว่าฉันมีแม่แบบ

<html>
<div>Hello {{name}}!</div>
</html>

ในขณะที่ทำการทดสอบมันจะมีประโยชน์ในการกำหนดค่าของตัวแปรโดยไม่ต้องแตะโค้ดไพ ธ อนที่เรียกใช้เทมเพลตนี้ ดังนั้นฉันกำลังมองหาบางอย่างเช่นนี้

{% set name="World" %}     
<html>
<div>Hello {{name}}!</div>
</html>

สิ่งนี้มีอยู่ใน Django หรือไม่?

คำตอบ:


327

คุณสามารถใช้withเทมเพลตแท็ก

{% with name="World" %}     
<html>
<div>Hello {{name}}!</div>
</html>
{% endwith %}

35
แต่คุณสามารถเปลี่ยนค่าของตัวแปรในด้วย?
David 天宇 Wong

2
ดูเหมือนว่าคุณไม่สามารถประกาศคอนเทนเนอร์ (ฉันได้ลองรายการและทูเปิล) ด้วยประโยค
Vladislav Ivanishin

หากคุณต้องการประกาศรายการให้ใช้ make_list docs.djangoproject.com/en/1.9/ref/templates/builtins/#make-list
MrValdez

3
Jinja บอกว่ามัน {% set myvar = value%} ทำไมมันไม่ทำงานใน django
holms

3
@holms เนื่องจาก Django ไม่ได้ใช้ Jinja :-) docs.djangoproject.com/en/1.7/topics/templates
elimisteve

50

สร้างเทมเพลตแท็ก:

แอปควรมีtemplatetagsไดเรกทอรีอยู่ในระดับเดียวกับmodels.pyและviews.pyอื่น ๆ หากยังไม่มีให้สร้าง - อย่าลืม__init__.pyไฟล์เพื่อให้แน่ใจว่าไดเรกทอรีนั้นถือว่าเป็นแพคเกจ Python

สร้างไฟล์ชื่อdefine_action.pyภายในไดเรกทอรีtemplatetagsด้วยรหัสต่อไปนี้:

from django import template
register = template.Library()

@register.simple_tag
def define(val=None):
  return val

หมายเหตุ:เซิร์ฟเวอร์การพัฒนาจะไม่รีสตาร์ทโดยอัตโนมัติ หลังจากเพิ่มtemplatetagsโมดูลคุณจะต้องรีสตาร์ทเซิร์ฟเวอร์ของคุณก่อนจึงจะสามารถใช้แท็กหรือตัวกรองในแม่แบบ


จากนั้นในเทมเพลตของคุณคุณสามารถกำหนดค่าให้กับบริบทดังนี้:

{% load define_action %}
{% if item %}

   {% define "Edit" as action %}

{% else %}

   {% define "Create" as action %}

{% endif %}


Would you like to {{action}} this item?

2
ในกรณีของฉันหลังจากวนนี้จะคืนค่าเก่า :(
holms

7
ในเวอร์ชันล่าสุดดูเหมือนว่าคุณสามารถใช้ simple_tag แทน assignment_tag (และมันใช้ได้กับฉัน)
Katharine Osborne

ปัญหาที่ฉันได้รับจากโซลูชันนี้คือมันปรากฏขึ้นซึ่งคุณไม่สามารถแทนที่ค่าได้
Jakub Jabłoński

ถ้าคุณต้องการใช้เทคนิคนี้เพื่อตั้งค่ารายการแทนที่จะเป็นเพียงค่าให้ตรวจสอบสิ่งนี้: stackoverflow.com/a/34407158/2193235
msb

ถ้าคุณมีการตั้งค่าตัวแปรจำนวนเต็มและคุณต้องการที่จะเพิ่มมัน (ตัวอย่าง) คุณจำเป็นต้องใช้:add {% define counter|add:1 as counter %}ในทำนองเดียวกันสำหรับการดำเนินงานอื่น ๆ
msb

35

อีกทางเลือกหนึ่งที่ไม่ต้องการให้คุณใส่ทุกอย่างในบล็อก "with" คือการสร้างแท็กที่กำหนดเองที่เพิ่มตัวแปรใหม่ให้กับบริบท ในขณะที่:

class SetVarNode(template.Node):
    def __init__(self, new_val, var_name):
        self.new_val = new_val
        self.var_name = var_name
    def render(self, context):
        context[self.var_name] = self.new_val
        return ''

import re
@register.tag
def setvar(parser,token):
    # This version uses a regular expression to parse tag contents.
    try:
        # Splitting by None == splitting by spaces.
        tag_name, arg = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents.split()[0]
    m = re.search(r'(.*?) as (\w+)', arg)
    if not m:
        raise template.TemplateSyntaxError, "%r tag had invalid arguments" % tag_name
    new_val, var_name = m.groups()
    if not (new_val[0] == new_val[-1] and new_val[0] in ('"', "'")):
        raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
    return SetVarNode(new_val[1:-1], var_name)

สิ่งนี้จะช่วยให้คุณสามารถเขียนสิ่งนี้ในเทมเพลตของคุณ:

{% setvar "a string" as new_template_var %}

โปรดทราบว่าสิ่งนี้ส่วนใหญ่นำมาจากที่นี่


วิธีการเกี่ยวกับการกำหนดตัวแปรให้กับตัวแปรอื่น ๆ ที่มีอยู่ในบริบทหรือไม่ และในบันทึกอื่น: การอนุญาตให้แม่แบบกำหนดตัวแปรบริบทโดยไม่มีการตรวจสอบหากมีอยู่แล้วอาจมีผลกระทบด้านความปลอดภัย วิธีการที่สมเหตุสมผลในความคิดของฉันคือการตรวจสอบบริบทของตัวแปรก่อนที่จะพยายามกำหนด:
แช่แข็ง

ถ้า context.get (self.var_name): เพิ่ม SuspiciousOperation ("พยายามกำหนดตัวแปรจากแม่แบบที่มีอยู่แล้วในบริบท")
แช่แข็ง

27

มีกลอุบายเหมือนที่จอห์นอธิบายไว้ อย่างไรก็ตามภาษาแม่แบบของ Django โดยการออกแบบไม่สนับสนุนการตั้งค่าตัวแปร (ดูที่กล่อง "ปรัชญา" ในเอกสารประกอบของ Django สำหรับแม่แบบ )
ด้วยเหตุนี้วิธีที่แนะนำให้เปลี่ยนตัวแปรคือการแตะรหัส Python


7
ขอบคุณสำหรับตัวชี้ จากมุมมองของนักออกแบบบางครั้งมันง่ายกว่าที่จะตั้งค่าตัวแปรอย่างรวดเร็วเพื่อทดสอบสถานะต่าง ๆ ของหน้าขณะที่ออกแบบ ไม่แนะนำให้ใช้วิธีนี้ในรหัสที่กำลังรัน
Alexis

2
ยอมรับแท็ก "with" ใน django1.0 ดูเหมือนว่าพวกเขากำลังแก้ไขปรัชญาของพวกเขาในที่สุด :)
Evgeny

2
ตามความจริงแล้วแท็ก "พร้อม" เป็นเพียงชื่อแทน สิ่งนี้อาจมีผลกระทบอย่างมากต่อประสิทธิภาพ (และความสามารถในการอ่านเช่นกัน!) แต่มันก็ไม่ได้ตั้งค่าตัวแปรในแง่โปรแกรมแบบดั้งเดิม
ปล้น

12

assignment_tagทางออกที่ดีที่สุดสำหรับเรื่องนี้คือการเขียนที่กำหนดเอง โซลูชันนี้สะอาดกว่าการใช้withแท็กเนื่องจากแยกได้ชัดเจนระหว่างตรรกะและสไตล์

เริ่มต้นด้วยการสร้างไฟล์แท็กเทมเพลต (เช่นappname/templatetags/hello_world.py):

from django import template

register = template.Library()

@register.assignment_tag
def get_addressee():
    return "World"

ตอนนี้คุณสามารถใช้get_addresseeแท็กแม่แบบในแม่แบบของคุณ:

{% load hello_world %}

{% get_addressee as addressee %}

<html>
    <body>
        <h1>hello {{addressee}}</h1>
    </body>
</html>

3
สำหรับคนที่ใช้ Django เวอร์ชั่นใหม่กว่านี้มันเรียกว่า simple_tag เลย! ประหยัดเวลาในการหาสาเหตุที่ทำให้ "register .. " ไม่เป็นที่รู้จักในรหัสของคุณ ...
kaya

11

บางทีdefaultตัวกรองแม่แบบไม่ใช่ตัวเลือกในปี 2009 ...

<html>
<div>Hello {{name|default:"World"}}!</div>
</html>

ฉันต้องบอกว่านี่คือสิ่งที่ฉันกำลังมองหา! มันยังสามารถใช้กับกับ : {% with state=form.state.value|default:other_context_variable %}แทนของother_context_variableเรายังสามารถใช้ใด ๆ'string_value'ได้เป็นอย่างดี
Saurav Kumar

แต่มันจะพิมพ์มันและฉันต้องเก็บไว้เพื่อใช้ในภายหลัง
Holms

4

ไม่ใช่ความคิดที่ดีโดยทั่วไป ทำตรรกะทั้งหมดในหลามและส่งผ่านข้อมูลไปยังเทมเพลตเพื่อแสดง เทมเพลตควรเรียบง่ายที่สุดเท่าที่จะเป็นไปได้เพื่อให้มั่นใจว่าผู้ที่ทำงานด้านการออกแบบสามารถมุ่งเน้นไปที่การออกแบบมากกว่าที่จะกังวลเกี่ยวกับตรรกะ

ในการยกตัวอย่างหากคุณต้องการข้อมูลที่ได้รับจากแม่แบบมันจะเป็นการดีกว่าถ้าคุณเข้าไปในตัวแปรในรหัสไพ ธ อนจากนั้นส่งผ่านไปยังเทมเพลต


3

ใช้กับคำสั่ง

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

ฉันไม่สามารถแปลรหัสในย่อหน้าแรกของคำตอบนี้ได้ บางทีภาษาแม่แบบอาจเลิกใช้รูปแบบเก่า


2

ในแม่แบบของคุณคุณสามารถทำสิ่งนี้:

{% jump_link as name %}
{% for obj in name %}
    <div>{{obj.helo}} - {{obj.how}}</div>
{% endfor %}

ในเทมเพลต - แท็กคุณสามารถเพิ่มแท็กดังนี้:

@register.assignment_tag
def jump_link():
    listArr = []
    for i in range(5):
        listArr.append({"helo" : i,"how" : i})
    return listArr
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.