Eu tenho algumas coisas em settings.py que gostaria de acessar de um modelo, mas não consigo descobrir como fazê-lo. Eu já tentei
{{CONSTANT_NAME}}
mas isso não parece funcionar. Isso é possível?
Eu tenho algumas coisas em settings.py que gostaria de acessar de um modelo, mas não consigo descobrir como fazê-lo. Eu já tentei
{{CONSTANT_NAME}}
mas isso não parece funcionar. Isso é possível?
Respostas:
O Django fornece acesso a certas constantes de configurações usadas com freqüência ao modelo como settings.MEDIA_URL
e algumas das configurações de idioma se você usar visualizações genéricas incorporadas pelo django ou passar um argumento de palavra-chave da instância de contexto na render_to_response
função de atalho. Aqui está um exemplo 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))
Essas visualizações terão várias configurações usadas com frequência, como settings.MEDIA_URL
disponíveis para o modelo como {{ MEDIA_URL }}
etc.
Se você estiver procurando acesso a outras constantes nas configurações, basta descompactar as constantes desejadas e adicioná-las ao dicionário de contexto que você está usando na função de visualização, da seguinte forma:
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)
Agora você pode acessar settings.FAVORITE_COLOR
no seu modelo como {{ favorite_color }}
.
django-settings-export
para evitar a necessidade de escrever esse código em todas as visualizações.
Se é um valor que você gostaria de ter para cada solicitação e modelo, usar um processador de contexto é mais apropriado.
Aqui está como:
Crie um context_processors.py
arquivo no diretório do seu aplicativo. Digamos que eu quero ter o ADMIN_PREFIX_VALUE
valor em todos os contextos:
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}
adicione seu processador de contexto ao seu arquivo settings.py :
TEMPLATES = [{
# whatever comes before
'OPTIONS': {
'context_processors': [
# whatever comes before
"your_app.context_processors.admin_media",
],
}
}]
Use RequestContext
na sua exibição para adicionar seus processadores de contexto ao seu modelo. O render
atalho faz isso automaticamente:
from django.shortcuts import render
def my_view(request):
return render(request, "index.html")
e, finalmente, no seu modelo:
...
<a href="{{ ADMIN_MEDIA_URL }}">path to admin media</a>
...
context_process.py
ao lado do meu settings.py
arquivo e adicionei "context_processors.admin_media"
à minha TEMPLATE_CONTEXT_PROCESSORS
lista. Além disso, convém adicionar uma observação em sua resposta sobre o fato de que o valor padrão de TEMPLATE_CONTEXT_PROCESSORS não está vazio; portanto, se algum código existente usar algum dos valores definidos por esses processadores de contexto padrão, eles não funcionarão, a menos que você os adicione novamente para a lista explicitamente.
render
atalho para evitar ter de incluir explicitamente RequestContext: docs.djangoproject.com/en/1.6/topics/http/shortcuts/#render
Acho que a abordagem mais simples é uma única tag de modelo personalizado :
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" %}
{% settings_value "DATABASES" %}
:? Esse caso de uso deve deixar óbvio por que as configurações não estão disponíveis nos modelos para começar.
templatetags
pasta dentro do seu aplicativo com um __init__.py
arquivo vazio e esse código settings.py
dentro dessa pasta. 2) no seu modelo você adiciona {% load settings %}
e depois usa sua nova tag!
Confira django-settings-export
(isenção de responsabilidade: sou o autor deste projeto).
Por exemplo...
$ pip install django-settings-export
TEMPLATES = [
{
'OPTIONS': {
'context_processors': [
'django_settings_export.settings_export',
],
},
},
]
MY_CHEESE = 'Camembert';
SETTINGS_EXPORT = [
'MY_CHEESE',
]
<script>var MY_CHEESE = '{{ settings.MY_CHEESE }}';</script>
render
e nãorender_to_response
Outra maneira de fazer isso é criar uma tag de modelo personalizada que pode permitir que você pesque valores fora das configurações.
@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))
Você pode então usar:
{% value_from_settings "FQDN" %}
imprimi-lo em qualquer página, sem pular os bastidores do processador de contexto.
Gosto da solução de Berislav, porque em sites simples ela é limpa e eficaz. O que eu NÃO gosto é de expor todas as constantes de configurações, quer ou não. Então o que acabei fazendo foi o seguinte:
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" %}
Isso protege todas as constantes que você não nomeou para uso no modelo e, se quiser ser realmente sofisticado, pode definir uma tupla nas configurações e criar mais de uma marca de modelo para diferentes páginas, aplicativos ou áreas, e simplesmente combine uma tupla local com a tupla de configurações, conforme necessário, e faça a compreensão da lista para ver se o valor é aceitável.
Concordo que, em um site complexo, isso é um pouco simplista, mas há valores que seria bom ter universalmente em modelos, e isso parece funcionar bem. Obrigado a Berislav pela ideia original!
if name in ALLOWABLE_VALUES: ...
'val' in ('val_first', 'second_val',)
é False
, não substring problema aqui.
if
declaração? Eu quero verificar o DEBUG
valor
Eu melhorei a resposta de chrisdew (para criar a sua própria etiqueta) um pouco.
Primeiro, crie o arquivo yourapp/templatetags/value_from_settings.py
no qual você define sua própria nova tag 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
Você pode usar essa tag no seu modelo por:
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" %}
ou via
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" as my_fqdn %}
A vantagem da as ...
notação é que isso facilita o uso em blocktrans
blocos por meio de um simples {{my_fqdn}}
.
Adicionando uma resposta com instruções completas para criar uma tag de modelo personalizada que resolve isso, com o Django 2.0+
Na sua pasta de aplicativos, crie uma pasta chamada tags de modelo . Nele, crie __init__.py e custom_tags.py :
No custom_tags.py, crie uma função de tag personalizada que forneça acesso a uma chave arbitrária na constante de configurações :
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 esse código, recomendo a leitura da seção sobre tags simples nos documentos do Django.
Então, você precisa tornar o Django ciente dessa tag personalizada (e de qualquer outra adicional) carregando esse arquivo em qualquer modelo em que você o usará. Assim como você precisa carregar a tag estática incorporada:
{% load custom_tags %}
Com ele carregado, ele pode ser usado como qualquer outra tag, basta fornecer a configuração específica que você precisa retornar. Portanto, se você tiver uma variável BUILD_VERSION em suas configurações:
{% get_setting "BUILD_VERSION" %}
Essa solução não funcionará com matrizes, mas se você precisar, poderá colocar muita lógica em seus modelos.
Nota: Uma solução mais limpa e à prova de falhas provavelmente seria criar um processador de contexto personalizado onde você adiciona as configurações necessárias a um contexto disponível para todos os modelos. Dessa forma, você reduz o risco de gerar configurações confidenciais em seus modelos por engano.
Adicione este código a um arquivo chamado context_processors.py
:
from django.conf import settings as django_settings
def settings(request):
return {
'settings': django_settings,
}
E, em seu arquivo de configurações, inclua um caminho como 'speedy.core.base.context_processors.settings'
(com o nome e o caminho do seu aplicativo) no diretório'context_processors'
configurações em TEMPLATES
.
(Você pode ver, por exemplo, settings / base.py e context_processors.py ).
Em seguida, você pode usar a configuração específica em qualquer código de modelo. Por exemplo:
{% if settings.SITE_ID == settings.SPEEDY_MATCH_SITE_ID %}
Atualização: o código acima expõe todas as configurações aos modelos, incluindo informações confidenciais como a sua SECRET_KEY
. Um hacker pode abusar desse recurso para exibir essas informações nos modelos. Se você deseja expor apenas configurações específicas aos modelos, use este código:
def settings(request):
settings_in_templates = {}
for attr in ["SITE_ID", ...]: # Write here the settings you want to expose to the templates.
if (hasattr(django_settings, attr)):
settings_in_templates[attr] = getattr(django_settings, attr)
return {
'settings': settings_in_templates,
}
SECRET_KEY
. Um hacker pode abusar desse recurso para exibir essas informações nos modelos.
O exemplo acima de bchhun é bom, exceto que você precisa criar explicitamente seu dicionário de contexto a partir de settings.py. Abaixo está um exemplo UNTESTED de como você pode criar automaticamente o dicionário de contexto a partir de todos os atributos em maiúsculas de settings.py (re: "^ [A-Z0-9 _] + $").
No 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',
...
)
Se alguém encontrar essa pergunta como eu, postarei minha solução que funciona no Django 2.0:
Essa tag atribui algum valor da variável settings.py à variável do modelo:
Uso: {% get_settings_value template_var "SETTINGS_VAR" %}
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)
{% 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 %}
... do something ...
{% else %}
... do other stuff ...
{% endif %}
Veja a documentação do Django como criar tags de modelo personalizadas aqui: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/
{% if settings_debug %}
{% if settings_debug == True %}
para o sugerido{% if settings_debug %}
Se estiver usando uma exibição baseada em classe:
#
# 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 }}
IanSR e bchhun sugeriram substituir TEMPLATE_CONTEXT_PROCESSORS nas configurações. Esteja ciente de que essa configuração tem um padrão que pode causar algumas coisas estranhas se você a substituir sem redefinir os padrões. Os padrões também foram alterados nas versões recentes do Django.
https://docs.djangoproject.com/en/1.3/ref/settings/#template-context-processors
O padrão TEMPLATE_CONTEXT_PROCESSORS:
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")
Se comparássemos as tags de contexto versus modelo em uma única variável, conhecer a opção mais eficiente poderia ser benéfico. No entanto, é melhor mergulhar nas configurações apenas de modelos que precisam dessa variável. Nesse caso, não faz sentido passar a variável para todos os modelos. Mas se você estiver enviando a variável para um modelo comum, como o modelo base.html, isso não importaria, pois o modelo base.html é renderizado em todas as solicitações, para que você possa usar os dois métodos.
Se você optar por usar a opção de tags de modelo, use o código a seguir, pois ele permite passar um valor padrão , caso a variável em questão não esteja definida.
Exemplo: get_from_settings my_variable como my_context_value
Exemplo: get_from_settings my_variable my_default como 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)