Come impostare un valore di una variabile all'interno di un codice modello?


217

Di 'che ho un modello

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

Durante il test, sarebbe utile definire il valore della variabile senza toccare il codice Python che invoca questo modello. Quindi sto cercando qualcosa del genere

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

Esiste qualcosa del genere in Django?

Risposte:


328

È possibile utilizzare il withtag modello.

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

35
ma puoi cambiare il valore della variabile in con?
David 天宇 Wong,

2
Sembra che tu non possa dichiarare un contenitore (ho provato l'elenco e la tupla) in una clausola with
Vladislav Ivanishin

Se devi dichiarare un elenco, usa make_list. docs.djangoproject.com/en/1.9/ref/templates/builtins/#make-list
MrValdez

3
Jinja dice che è {% set myvar = value%} perché non funziona in Django?
holms

3
@holms Perché Django non usa Jinja :-) docs.djangoproject.com/en/1.7/topics/templates
elimisteve

50

Crea un tag modello:

L'app dovrebbe contenere una templatetagsdirectory, allo stesso livello di models.py, views.pyecc. Se questo non esiste già, crealo - non dimenticare il __init__.pyfile per assicurarti che la directory sia trattata come un pacchetto Python.

Creare un file denominato define_action.pyall'interno della directory templatetags con il seguente codice:

from django import template
register = template.Library()

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

Nota: il server di sviluppo non si riavvierà automaticamente. Dopo aver aggiunto il templatetagsmodulo, sarà necessario riavviare il server prima di poter utilizzare i tag o i filtri nei modelli.


Quindi nel tuo modello puoi assegnare valori al contesto in questo modo:

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

   {% define "Edit" as action %}

{% else %}

   {% define "Create" as action %}

{% endif %}


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

2
nel mio caso dopo ciclo questo ritorna vecchio valore :(
holms

7
Nell'ultima versione sembra che puoi usare simple_tag invece di assegnatoment_tag (e ha funzionato per me).
Katharine Osborne,

Il problema che ho riscontrato con questa soluzione è che sembra che non sia possibile ignorare i valori.
Jakub Jabłoński,

se si desidera utilizzare questa tecnica per impostare un elenco anziché solo un valore, controllare questo: stackoverflow.com/a/34407158/2193235
msb

se si sta impostando la variabile come un intero e che si desidera incrementarlo (per esempio), è necessario utilizzare add: {% define counter|add:1 as counter %}. Allo stesso modo per altre operazioni.
msb

35

Un modo alternativo che non richiede di inserire tutto nel blocco "con" è quello di creare un tag personalizzato che aggiunge una nuova variabile al contesto. Come in:

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)

Questo ti permetterà di scrivere qualcosa del genere nel tuo modello:

{% setvar "a string" as new_template_var %}

Si noti che la maggior parte di questo è stata presa da qui


Che ne dici di assegnare variabili ad altre variabili presenti nel contesto? E su una nota diversa: consentire ai modelli di assegnare arbitrariamente variabili di contesto senza verificare se esistono già può avere implicazioni per la sicurezza. Un approccio più sensato secondo me sarebbe quello di controllare il contesto per la variabile prima di tentare di assegnarla:
soze

if context.get (self.var_name): raise SuspiciousOperation ("Tentativo di assegnare variabile dal modello già presente nel contesto")
Soze

27

Ci sono trucchi come quello descritto da John; tuttavia, il linguaggio dei modelli di Django in base alla progettazione non supporta l'impostazione di una variabile (vedere la casella "Filosofia" nella documentazione di Django per i modelli ).
Per questo motivo, il modo consigliato per modificare qualsiasi variabile è toccando il codice Python.


7
Grazie per il puntatore. Dal punto di vista di un designer a volte è più facile impostare rapidamente una variabile per testare vari stati di una pagina durante la progettazione. Non suggerire questa pratica da utilizzare in un codice in esecuzione.
Alexis,

2
il tag "with" è accettato in django1.0. Quindi sembra che stiano finalmente modificando la loro filosofia :).
Evgeny,

2
È un dato di fatto, il tag "with" è solo per alias. Questo può avere un impatto enorme sulle prestazioni (e anche sulla leggibilità!), Ma non sta davvero impostando una variabile in termini di programmazione tradizionale.
rapina il

12

La soluzione migliore per questo è scrivere un'abitudine assignment_tag. Questa soluzione è più pulita rispetto all'utilizzo di un withtag perché consente una separazione molto chiara tra logica e stile.

Inizia creando un file tag modello (ad es. appname/templatetags/hello_world.py):

from django import template

register = template.Library()

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

Ora puoi usare il get_addresseetag template nei tuoi template:

{% load hello_world %}

{% get_addressee as addressee %}

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

3
Per chi usa le versioni Django più recenti, ora si chiama simple_tag! Risparmia tempo per capire perché "registrati .." non è riconosciuto nel tuo codice ...
kaya,

11

Forse il defaultfiltro template non era un'opzione nel 2009 ...

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

Devo dire che questo è quello che stavo cercando! Può essere anche essere utilizzato con con : {% with state=form.state.value|default:other_context_variable %}anziché other_context_variablepossiamo anche usare qualsiasi 'string_value'pure
Saurav Kumar

Ma lo stamperà e devo salvarlo per un uso successivo
holms il

4

Questa non è una buona idea in generale. Esegui tutta la logica in Python e passa i dati al modello per la visualizzazione. Il modello dovrebbe essere il più semplice possibile per garantire che coloro che lavorano sulla progettazione possano concentrarsi sulla progettazione piuttosto che preoccuparsi della logica.

Per fare un esempio, se hai bisogno di alcune informazioni derivate all'interno di un modello, è meglio inserirle in una variabile nel codice Python e quindi passarle al modello.


3

Utilizzare il dichiarazione with .

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

Non posso implicare il codice nel primo paragrafo di questa risposta . Forse il linguaggio dei template aveva deprecato il vecchio formato.


2

Nel tuo modello puoi fare così:

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

Nei tag modello è possibile aggiungere un tag come questo:

@register.assignment_tag
def jump_link():
    listArr = []
    for i in range(5):
        listArr.append({"helo" : i,"how" : i})
    return listArr
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.