Bagaimana cara menetapkan nilai variabel di dalam kode templat?

216

Katakanlah saya punya template

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

Saat mengujinya, akan berguna untuk menentukan nilai variabel tanpa menyentuh kode python yang memanggil template ini. Jadi saya mencari sesuatu seperti ini

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

Apakah ada yang seperti ini di Django?

Alexis
sumber

Jawaban:

327

Anda dapat menggunakan withtag templat.

{% with name="World" %}     
<html>
<div>Hello {{name}}!</div>
</html>
{% endwith %}
John
sumber
35
tetapi dapatkah Anda mengubah nilai variabel dengan?
David 天宇 Wong
2
Tampaknya Anda tidak dapat mendeklarasikan sebuah wadah (Saya sudah mencoba daftar dan tuple) di dengan klausa
Vladislav Ivanishin
Jika Anda perlu mendeklarasikan daftar, gunakan make_list. docs.djangoproject.com/en/1.9/ref/templates/builtins/#make-list
MrValdez
3
Jinja mengatakan itu {% set myvar = value%} mengapa tidak bekerja di Django?
holms
3
@holms Karena Django tidak menggunakan Jinja :-) docs.djangoproject.com/en/1.7/topics/templates
elimisteve
50

Buat tag templat:

Aplikasi harus berisi templatetagsdirektori, pada tingkat yang sama dengan models.py,, views.pydll. Jika ini belum ada, buatlah - jangan lupa __init__.pyfile untuk memastikan direktori diperlakukan sebagai paket Python.

Buat file dengan nama define_action.pydi dalam direktori templatetags dengan kode berikut:

from django import template
register = template.Library()

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

Catatan: Server pengembangan tidak akan memulai ulang secara otomatis. Setelah menambahkan templatetagsmodul, Anda harus me-restart server Anda sebelum Anda dapat menggunakan tag atau filter dalam template.


Kemudian di templat Anda, Anda dapat menetapkan nilai ke konteks seperti ini:

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

   {% define "Edit" as action %}

{% else %}

   {% define "Create" as action %}

{% endif %}


Would you like to {{action}} this item?
Mods Vs Rockers
sumber
2
dalam kasus saya setelah loop ini mengembalikan nilai lama :(
holms
7
Dalam versi terbaru tampaknya Anda dapat menggunakan simple_tag alih-alih assignment_tag (dan itu berhasil untuk saya).
Katharine Osborne
Masalah yang saya dapatkan dengan solusi ini adalah bahwa itu muncul, bahwa Anda tidak dapat mengesampingkan nilai.
Jakub Jabłoński
jika Anda ingin menggunakan teknik ini untuk menetapkan daftar alih-alih hanya nilai, periksa ini: stackoverflow.com/a/34407158/2193235
msb
jika Anda menetapkan variabel sebagai integer dan Anda ingin kenaikan itu (misalnya), Anda perlu menggunakan add: {% define counter|add:1 as counter %}. Demikian pula untuk operasi lain.
msb
35

Cara alternatif yang tidak mengharuskan Anda meletakkan segala sesuatu di blok "with" adalah membuat tag khusus yang menambahkan variabel baru ke konteksnya. Seperti dalam:

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)

Ini akan memungkinkan Anda untuk menulis sesuatu seperti ini di templat Anda:

{% setvar "a string" as new_template_var %}

Perhatikan bahwa sebagian besar diambil dari sini

Karim
sumber
Bagaimana dengan menempatkan variabel ke variabel lain yang ada dalam konteks? Dan pada catatan yang berbeda: memungkinkan templat untuk secara sewenang-wenang menetapkan variabel konteks tanpa memeriksa jika ada, mungkin memiliki implikasi keamanan. Pendekatan yang lebih masuk akal menurut saya akan memeriksa konteks untuk variabel sebelum mencoba untuk menugaskannya:
soze
jika context.get (self.var_name): naikkan SuspiciousOperation ("Berusaha menetapkan variabel dari templat yang sudah ada dalam konteks")
soze
27

Ada trik seperti yang dijelaskan oleh John; namun, bahasa template Django menurut desain tidak mendukung pengaturan variabel (lihat kotak "Philosophy" dalam dokumentasi Django untuk templat ).
Karena itu, cara yang disarankan untuk mengubah variabel apa pun adalah dengan menyentuh kode Python.

rampok
sumber
7
Terima kasih untuk penunjuknya. Dari sudut pandang seorang desainer, terkadang lebih mudah mengatur variabel dengan cepat untuk menguji berbagai kondisi halaman saat mendesainnya. Tidak menyarankan praktik ini untuk digunakan dalam kode yang sedang berjalan.
Alexis
2
tag "with" diterima di django1.0. Jadi sepertinya mereka akhirnya mengubah filosofi mereka :).
Evgeny
2
Faktanya, tag "with" hanya untuk alias. Ini mungkin memiliki dampak besar pada kinerja (dan pada keterbacaan juga!) Tetapi tidak benar-benar menetapkan variabel dalam istilah pemrograman tradisional.
merampok
12

Solusi terbaik untuk ini adalah dengan menulis kebiasaan assignment_tag. Solusi ini lebih bersih daripada menggunakan withtag karena memberikan pemisahan yang sangat jelas antara logika dan gaya.

Mulai dengan membuat file tag templat (mis. appname/templatetags/hello_world.py):

from django import template

register = template.Library()

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

Sekarang Anda dapat menggunakan get_addresseetag templat di templat Anda:

{% load hello_world %}

{% get_addressee as addressee %}

<html>
    <body>
        <h1>hello {{addressee}}</h1>
    </body>
</html>
entitas yang unik
sumber
3
Untuk orang-orang yang menggunakan versi Django yang lebih baru, sekarang disebut simple_tag! Hemat waktu untuk mencari tahu mengapa "daftar .." tidak dikenali dalam kode Anda ...
kaya
11

Mungkin defaultfilter templat bukan opsi kembali pada tahun 2009 ...

<html>
<div>Hello {{name|default:"World"}}!</div>
</html>
John Mee
sumber
Saya harus mengatakan bahwa inilah yang saya cari! Hal ini dapat juga digunakan dengan dengan : {% with state=form.state.value|default:other_context_variable %}bukannya other_context_variablekita juga dapat menggunakan 'string_value'juga
Saurav Kumar
Tapi itu akan mencetaknya, dan saya harus menyimpannya untuk digunakan nanti
holms
4

Ini bukan ide yang baik secara umum. Lakukan semua logika dengan python dan berikan data ke templat untuk ditampilkan. Template harus sesederhana mungkin untuk memastikan mereka yang bekerja pada desain dapat fokus pada desain daripada khawatir tentang logika.

Untuk memberikan contoh, jika Anda memerlukan beberapa informasi turunan dalam templat, lebih baik memasukkannya ke dalam variabel dalam kode python dan kemudian meneruskannya ke templat.

Sarang
sumber
3

Gunakan pernyataan with .

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

Saya tidak dapat menyiratkan kode pada paragraf pertama dalam jawaban ini . Mungkin bahasa templat telah meninggalkan format lama.

ramwin
sumber
2

Di template Anda, Anda dapat melakukan hal ini:

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

Dalam tag-template Anda, Anda dapat menambahkan tag seperti ini:

@register.assignment_tag
def jump_link():
    listArr = []
    for i in range(5):
        listArr.append({"helo" : i,"how" : i})
    return listArr
Ashish Gupta
sumber