Definindo “variável global” em modelos de django
-
06-07-2019 - |
Pergunta
Estou fazendo algo como:
{% extends 'base.html' %}
{% url myapp.views.dashboard object as object_url %}
{% block sidebar %}
... {{ object_url }} ...
{% endblock %}
{% block content %}
... {{ object_url }} ...
{% endblock %}
A documentação do Django diz object_url
nos blocos a seguir.
Se eu colocar o URL TemplateTag no início de cada bloco, ele funciona, mas não quero "me repetir".
Alguém conhece uma solução melhor?
Solução
Se o URL for específico, você poderá passar o URL da sua opinião. Se o URL precisar ser verdadeiramente global em seus modelos, você pode colocá -lo em Um processador de contexto:
def object_url(request):
return {'object_url': reverse('myapp.views.dashboard')}
Outras dicas
Parece que isso foi respondido antes, mas há uma alternativa. Uma coisa é usar um processador de contexto para acompanhar algo definido de fora do modelo, mas às vezes você deseja contar o número de vezes que dois loops passam ou algo assim. Há outra maneira:
class GlobalVariable(object):
def __init__(self, varname, varval):
self.varname = varname
self.varval = varval
def name(self):
return self.varname
def value(self):
return self.varval
def set(self, newval):
self.varval = newval
class GlobalVariableSetNode(template.Node):
def __init__(self, varname, varval):
self.varname = varname
self.varval = varval
def render(self, context):
gv = context.get(self.varname, None)
if gv:
gv.set(self.varval)
else:
gv = context[self.varname] = GlobalVariable(
self.varname, self.varval)
return ''
def setglobal(parser, token):
try:
tag_name, varname, varval = token.contents.split(None, 2)
except ValueError:
raise template.TemplateSyntaxError(
"%r tag requires 2 arguments" % token.contents.split()[0])
return GlobalVariableSetNode(varname, varval)
register.tag('setglobal', setglobal)
class GlobalVariableGetNode(template.Node):
def __init__(self, varname):
self.varname = varname
def render(self, context):
try:
return context[self.varname].value()
except AttributeError:
return ''
def getglobal(parser, token):
try:
tag_name, varname = token.contents.split(None, 1)
except ValueError:
raise template.TemplateSyntaxError(
"%r tag requires arguments" % token.contents.split()[0])
return GlobalVariableGetNode(varname)
register.tag('getglobal', getglobal)
class GlobalVariableIncrementNode(template.Node):
def __init__(self, varname):
self.varname = varname
def render(self, context):
gv = context.get(self.varname, None)
if gv is None:
return ''
gv.set(int(gv.value()) + 1)
return ''
def incrementglobal(parser, token):
try:
tag_name, varname = token.contents.split(None, 1)
except ValueError:
raise template.TemplateSyntaxError(
"%r tag requires arguments" % token.contents.split()[0])
return GlobalVariableIncrementNode(varname)
register.tag('incrementglobal', incrementglobal)
Isso permite que você o use em um modelo como este:
{% setglobal ii 0 %}
...
{% for ... %}
{% incrementglobal ii %}
current={% getglobal ii %}
{% endfor %}
...
{% for ... %}
{% incrementglobal ii %}
current={% getglobal ii %}
{% endfor %}
...
total of 2 loops={% getglobal ii %}
...
{% setglobal ii 0 %}
...
do something else now that {% getglobal ii %} is back to 0
Você pode escrever uma tag de modelo personalizada:
@register.simple_tag(takes_context=True)
def set_global_context(context, key, value):
"""
Sets a value to the global template context, so it can
be accessible across blocks.
Note that the block where the global context variable is set must appear
before the other blocks using the variable IN THE BASE TEMPLATE. The order
of the blocks in the extending template is not important.
Usage::
{% extends 'base.html' %}
{% block first %}
{% set_global_context 'foo' 'bar' %}
{% endblock %}
{% block second %}
{{ foo }}
{% endblock %}
"""
context.dicts[0][key] = value
return ''
Bem, isso é meio abusivo de herança de modelo, mas você pode usar {{block.super}}
Para colocar object_url em seus blocos.
Em outras palavras, em seu modelo de nível médio:
{% block sidebar %}{{ object_url }}{% endblock %}
{% block content %}{{ object_url }}{% endblock %}
E então, em seus modelos de bloco, use:
{% block sidebar %}
... {{ block.super }}...
{% endblock %}
Não é uma ótima ideia, porque impede que você coloque qualquer coisa além {{ object_url }}
em seu quarteirão ... mas funciona. Só não diga a ninguém que você conseguiu de mim!
Em todos os modelos herdados, qualquer código fora dos blocos de redefinições não é executado. Então, no seu exemplo, você tem que ligar {% url %}
Marque dentro de cada bloco ou use o processador de contexto para definir a variável "global".