¿Puedo acceder a las constantes en settings.py desde plantillas en Django?
django-templates django-settings (14)
Django proporciona acceso a ciertas constantes de configuración de uso frecuente de la plantilla, como settings.MEDIA_URL
y algunas de las configuraciones de idioma si utiliza las vistas genéricas integradas de django o pasa un argumento de palabra clave de instancia de contexto en la función de acceso directo render_to_response
. Aquí hay un ejemplo de cada caso:
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.generic.simple import direct_to_template
def my_generic_view(request, template=''my_template.html''):
return direct_to_template(request, template)
def more_custom_view(request, template=''my_template.html''):
return render_to_response(template, {}, context_instance=RequestContext(request))
Estas vistas tendrán varias configuraciones de uso frecuente, como la settings.MEDIA_URL
disponible para la plantilla como {{ MEDIA_URL }}
, etc.
Si está buscando acceso a otras constantes en la configuración, simplemente descomprima las constantes que desee y agréguelas al diccionario de contexto que está usando en su función de visualización, así:
from django.conf import settings
from django.shortcuts import render_to_response
def my_view_function(request, template=''my_template.html''):
context = {''favorite_color'': settings.FAVORITE_COLOR}
return render_to_response(template, context)
Ahora puedes acceder a la settings.FAVORITE_COLOR
en tu plantilla como {{ favorite_color }}
.
Tengo algunas cosas en settings.py a las que me gustaría poder acceder desde una plantilla, pero no sé cómo hacerlo. Ya lo intente
{{CONSTANT_NAME}}
pero eso no parece funcionar. es posible?
Echa un vistazo a django-settings-export
(descargo de responsabilidad: soy el autor de este proyecto).
Por ejemplo...
$ pip install django-settings-export
settings.py
TEMPLATES = [
{
''OPTIONS'': {
''context_processors'': [
''django_settings_export.settings_export'',
],
},
},
]
MY_CHEESE = ''Camembert'';
SETTINGS_EXPORT = [
''MY_CHEESE'',
]
template.html
<script>var MY_CHEESE = ''{{ settings.MY_CHEESE }}'';</script>
El ejemplo anterior de bchhun es bueno, excepto que necesita crear explícitamente su diccionario de contexto desde settings.py. A continuación se muestra un ejemplo SIN PRUEBAS de cómo podría construir automáticamente el diccionario de contexto a partir de todos los atributos en mayúsculas de settings.py (re: "^ [A-Z0-9 _] + $").
Al final de settings.py:
_context = {}
local_context = locals()
for (k,v) in local_context.items():
if re.search(''^[A-Z0-9_]+$'',k):
_context[k] = str(v)
def settings_context(context):
return _context
TEMPLATE_CONTEXT_PROCESSORS = (
...
''myproject.settings.settings_context'',
...
)
Encontré que este es el enfoque más simple para Django 1.3:
vistas.py
from local_settings import BASE_URL def root(request): return render_to_response(''hero.html'', {''BASE_URL'': BASE_URL})
hero.html
var BASE_URL = ''{{ JS_BASE_URL }}'';
Encuentro que el enfoque más simple es una etiqueta de plantilla única:
from django import template
from django.conf import settings
register = template.Library()
# settings value
@register.simple_tag
def settings_value(name):
return getattr(settings, name, "")
Uso:
{% settings_value "LANGUAGE_CODE" %}
Me gusta la solución de Berislav, porque en sitios simples es limpia y efectiva. Lo que NO me gusta es exponer todas las constantes de configuración de cualquier manera. Entonces lo que terminé haciendo fue esto:
from django import template
from django.conf import settings
register = template.Library()
ALLOWABLE_VALUES = ("CONSTANT_NAME_1", "CONSTANT_NAME_2",)
# settings value
@register.simple_tag
def settings_value(name):
if name in ALLOWABLE_VALUES:
return getattr(settings, name, '''')
return ''''
Uso:
{% settings_value "CONSTANT_NAME_1" %}
Esto protege las constantes que no haya nombrado de su uso en la plantilla, y si deseaba obtener un diseño realmente lujoso, podría establecer una tupla en la configuración y crear más de una etiqueta de plantilla para diferentes páginas, aplicaciones o áreas, y simplemente combine una tupla local con la tupla de configuración según sea necesario, luego haga la comprensión de la lista para ver si el valor es aceptable.
Estoy de acuerdo, en un sitio complejo, esto es un poco simplista, pero hay valores que sería bueno tener universalmente en las plantillas, y esto parece funcionar bien. Gracias a Berislav por la idea original!
Otra forma de hacer esto es crear una etiqueta de plantilla personalizada que le permita capturar valores fuera de la configuración.
@register.tag
def value_from_settings(parser, token):
try:
# split_contents() knows not to split quoted strings.
tag_name, var = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents.split()[0]
return ValueFromSettings(var)
class ValueFromSettings(template.Node):
def __init__(self, var):
self.arg = template.Variable(var)
def render(self, context):
return settings.__getattr__(str(self.arg))
A continuación, puede utilizar:
{% value_from_settings "FQDN" %}
para imprimirlo en cualquier página, sin saltar a través de aros de procesador de contexto.
Si alguien encuentra esta pregunta como yo, publicaremos mi solución que funciona en Django 2.0:
Esta etiqueta asigna un valor variable de settings.py a la variable de la plantilla:
Uso: {% get_settings_value template_var "SETTINGS_VAR" %}
app / templatetags / my_custom_tags.py:
from django import template
from django.conf import settings
register = template.Library()
class AssignNode(template.Node):
def __init__(self, name, value):
self.name = name
self.value = value
def render(self, context):
context[self.name] = getattr(settings, self.value.resolve(context, True), "")
return ''''
@register.tag(''get_settings_value'')
def do_assign(parser, token):
bits = token.split_contents()
if len(bits) != 3:
raise template.TemplateSyntaxError("''%s'' tag takes two arguments" % bits[0])
value = parser.compile_filter(bits[2])
return AssignNode(bits[1], value)
Su plantilla:
{% load my_custom_tags %}
# Set local template variable:
{% get_settings_value settings_debug "DEBUG" %}
# Output settings_debug variable:
{{ settings_debug }}
# Use variable in if statement:
{% if settings_debug == True %}
... do something ...
{% else %}
... do other stuff ...
{% endif %}
Consulte la documentación de Django sobre cómo crear etiquetas de plantillas personalizadas aquí: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/
Si es un valor que le gustaría tener para cada solicitud y plantilla, usar un procesador de contexto es más apropiado.
Así es cómo:
Cree un archivo
context_processors.py
en el directorio de su aplicación. Digamos que quiero tener el valorADMIN_PREFIX_VALUE
en cada contexto:from django.conf import settings # import the settings file def admin_media(request): # return the value you want as a dictionnary. you may add multiple values in there. return {''ADMIN_MEDIA_URL'': settings.ADMIN_MEDIA_PREFIX}
agrega tu procesador de contexto a tu archivo settings.py :
TEMPLATES = [{ # whatever comes before ''OPTIONS'': { ''context_processors'': [ # whatever comes before "your_app.context_processors.admin_media", ], } }]
Use
RequestContext
en su vista para agregar sus procesadores de contexto en su plantilla. El atajo derender
hace esto automáticamente:from django.shortcuts import render def my_view(request): return render(request, "index.html")
y finalmente, en tu plantilla:
... <a href="{{ ADMIN_MEDIA_URL }}">path to admin media</a> ...
Si tuviéramos que comparar las etiquetas de contexto con las de plantilla en una sola variable, entonces conocer la opción más eficiente podría ser beneficioso. Sin embargo, es mejor que te sumerjas en la configuración solo de las plantillas que necesitan esa variable. En ese caso, no tiene sentido pasar la variable a todas las plantillas. Pero si está enviando la variable a una plantilla común, como la plantilla base.html, no importará, ya que la plantilla base.html se representa en cada solicitud, por lo que puede usar cualquiera de los dos métodos.
Si decide utilizar la opción de etiquetas de plantilla, use el siguiente código, ya que le permite pasar un valor predeterminado , en caso de que la variable en cuestión no estuviera definida.
Ejemplo: get_from_settings my_variable as my_context_value
Ejemplo: get_from_settings my_variable my_default as my_context_value
class SettingsAttrNode(Node):
def __init__(self, variable, default, as_value):
self.variable = getattr(settings, variable, default)
self.cxtname = as_value
def render(self, context):
context[self.cxtname] = self.variable
return ''''
def get_from_setting(parser, token):
as_value = variable = default = ''''
bits = token.contents.split()
if len(bits) == 4 and bits[2] == ''as'':
variable = bits[1]
as_value = bits[3]
elif len(bits) == 5 and bits[3] == ''as'':
variable = bits[1]
default = bits[2]
as_value = bits[4]
else:
raise TemplateSyntaxError, "usage: get_from_settings variable default as value " /
"OR: get_from_settings variable as value"
return SettingsAttrNode(variable=variable, default=default, as_value=as_value)
get_from_setting = register.tag(get_from_setting)
Si usa una vista basada en clase:
#
# in settings.py
#
YOUR_CUSTOM_SETTING = ''some value''
#
# in views.py
#
from django.conf import settings #for getting settings vars
class YourView(DetailView): #assuming DetailView; whatever though
# ...
def get_context_data(self, **kwargs):
context = super(YourView, self).get_context_data(**kwargs)
context[''YOUR_CUSTOM_SETTING''] = settings.YOUR_CUSTOM_SETTING
return context
#
# in your_template.html, reference the setting like any other context variable
#
{{ YOUR_CUSTOM_SETTING }}
Tanto IanSR como bchhun sugirieron anular TEMPLATE_CONTEXT_PROCESSORS en la configuración. Tenga en cuenta que esta configuración tiene un valor predeterminado que puede causar algunos problemas si lo reemplaza sin restablecer los valores predeterminados. Los valores predeterminados también han cambiado en las versiones recientes de Django.
https://docs.djangoproject.com/en/1.3/ref/settings/#template-context-processors
Los TEMPLATE_CONTEXT_PROCESSORS predeterminados:
TEMPLATE_CONTEXT_PROCESSORS = ("django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.contrib.messages.context_processors.messages")
Mejoré un poco la respuesta de chrisdew (para crear tu propia etiqueta).
Primero, cree el archivo yourapp/templatetags/value_from_settings.py
en el que define su propia etiqueta nueva value_from_settings
:
from django.template import TemplateSyntaxError, Variable, Node, Variable, Library
from yourapp import settings
register = Library()
# I found some tricks in URLNode and url from defaulttags.py:
# https://code.djangoproject.com/browser/django/trunk/django/template/defaulttags.py
@register.tag
def value_from_settings(parser, token):
bits = token.split_contents()
if len(bits) < 2:
raise TemplateSyntaxError("''%s'' takes at least one " /
"argument (settings constant to retrieve)" % bits[0])
settingsvar = bits[1]
settingsvar = settingsvar[1:-1] if settingsvar[0] == ''"'' else settingsvar
asvar = None
bits = bits[2:]
if len(bits) >= 2 and bits[-2] == ''as'':
asvar = bits[-1]
bits = bits[:-2]
if len(bits):
raise TemplateSyntaxError("''value_from_settings'' didn''t recognise " /
"the arguments ''%s''" % ", ".join(bits))
return ValueFromSettings(settingsvar, asvar)
class ValueFromSettings(Node):
def __init__(self, settingsvar, asvar):
self.arg = Variable(settingsvar)
self.asvar = asvar
def render(self, context):
ret_val = getattr(settings,str(self.arg))
if self.asvar:
context[self.asvar] = ret_val
return ''''
else:
return ret_val
Puedes usar esta etiqueta en tu plantilla a través de:
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" %}
o via
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" as my_fqdn %}
La ventaja de la notación as ...
es que hace que sea fácil de usar en bloques blocktrans
través de un simple {{my_fqdn}}
.
Agregando una respuesta con instrucciones completas para crear una etiqueta de plantilla personalizada que solucione esto, con Django 2.0+
En su carpeta de aplicaciones, cree una carpeta llamada templatetags . En él, cree __init__.py y custom_tags.py :
En custom_tags.py, cree una función de etiqueta personalizada que proporcione acceso a una clave arbitraria en la constante de configuración :
from django import template
from django.conf import settings
register = template.Library()
@register.simple_tag
def get_setting(name):
return getattr(settings, name, "")
Para entender este código, recomiendo leer la sección sobre etiquetas simples en los documentos de Django.
Luego, necesita que Django se dé cuenta de esto (y de cualquier etiqueta personalizada) cargando este archivo en cualquier plantilla donde lo use. Al igual que necesitas cargar la etiqueta estática integrada:
{% load custom_tags %}
Una vez cargado, se puede usar como cualquier otra etiqueta, solo proporcione la configuración específica que necesita que se devuelva. Entonces, si tienes una variable BUILD_VERSION en tu configuración:
{% get_setting "BUILD_VERSION" %}
Esta solución no funcionará con matrices, pero si necesita eso, puede estar poniendo mucha lógica en sus plantillas.