Ho alcune cose in settings.py a cui vorrei poter accedere da un modello, ma non riesco a capire come farlo. Ci ho già provato
{{CONSTANT_NAME}}
ma questo non sembra funzionare. È possibile?
Ho alcune cose in settings.py a cui vorrei poter accedere da un modello, ma non riesco a capire come farlo. Ci ho già provato
{{CONSTANT_NAME}}
ma questo non sembra funzionare. È possibile?
Risposte:
Django fornisce l'accesso a determinate costanti di impostazioni utilizzate di frequente al modello come settings.MEDIA_URL
e ad alcune delle impostazioni della lingua se si utilizzano le viste generiche incorporate di django o si passa a un argomento della parola chiave dell'istanza di contesto nella render_to_response
funzione di scelta rapida. Ecco un esempio di ciascun 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))
Queste viste avranno entrambe diverse impostazioni usate frequentemente come settings.MEDIA_URL
disponibili per il modello come{{ MEDIA_URL }}
, ecc.
Se stai cercando l'accesso ad altre costanti nelle impostazioni, decomprimi semplicemente le costanti che desideri e aggiungile al dizionario di contesto che stai utilizzando nella tua funzione di visualizzazione, in questo modo:
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)
Ora puoi accedere settings.FAVORITE_COLOR
al tuo modello come {{ favorite_color }}
.
django-settings-export
di evitare la necessità di scrivere questo codice in ogni vista.
Se è un valore che desideri avere per ogni richiesta e modello, utilizzando un processore di contesto è più appropriato .
Ecco come:
Crea un context_processors.py
file nella directory dell'app. Diciamo che voglio avere il ADMIN_PREFIX_VALUE
valore in ogni contesto:
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}
aggiungi il tuo processore di contesto al tuo file settings.py :
TEMPLATES = [{
# whatever comes before
'OPTIONS': {
'context_processors': [
# whatever comes before
"your_app.context_processors.admin_media",
],
}
}]
Utilizzare RequestContext
nella vista per aggiungere i processori di contesto nel modello. Il render
collegamento fa automaticamente questo:
from django.shortcuts import render
def my_view(request):
return render(request, "index.html")
e infine, nel tuo modello:
...
<a href="{{ ADMIN_MEDIA_URL }}">path to admin media</a>
...
context_process.py
proprio accanto al mio settings.py
file e aggiunto "context_processors.admin_media"
alla mia TEMPLATE_CONTEXT_PROCESSORS
lista. Inoltre, potresti voler aggiungere una nota nella tua risposta sul fatto che il valore predefinito di TEMPLATE_CONTEXT_PROCESSORS non è vuoto, quindi se un codice esistente utilizza uno dei valori impostati da tali processori di contesto predefiniti, non funzioneranno se non li aggiungi di nuovo all'elenco esplicitamente.
render
collegamento per evitare di includere esplicitamente RequestContext: docs.djangoproject.com/en/1.6/topics/http/shortcuts/#render
Trovo che l'approccio più semplice sia un singolo tag modello personalizzato :
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" %}
:? Questo caso d'uso dovrebbe rendere ovvio il motivo per cui le impostazioni non sono disponibili nei modelli all'inizio.
templatetags
cartella all'interno della tua app con un __init__.py
file vuoto e questo codice come settings.py
all'interno di quella cartella. 2) nel tuo modello aggiungi {% load settings %}
e poi usi il tuo nuovo tag!
Check out django-settings-export
(disclaimer: sono l'autore di questo progetto).
Per esempio...
$ 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 nonrender_to_response
Un altro modo per farlo è quello di creare un tag modello personalizzato che ti permetta di pescare valori fuori dalle impostazioni.
@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))
È quindi possibile utilizzare:
{% value_from_settings "FQDN" %}
per stamparlo su qualsiasi pagina, senza saltare attraverso i cerchi del processore di contesto.
Mi piace la soluzione di Berislav, perché su siti semplici, è pulita ed efficace. Quello che NON mi piace è esporre tutte le costanti delle impostazioni, volenti o nolenti. Quindi quello che ho finito per fare è stato questo:
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" %}
Questo protegge qualsiasi costante che non hai nominato dall'uso nel modello e, se vuoi essere davvero fantasioso, potresti impostare una tupla nelle impostazioni e creare più di un tag modello per pagine, app o aree diverse e semplicemente combinare una tupla locale con la tupla delle impostazioni in base alle esigenze, quindi fare la comprensione dell'elenco per vedere se il valore è accettabile.
Sono d'accordo, su un sito complesso, questo è un po 'semplicistico, ma ci sono valori che sarebbe bello avere universalmente nei template, e questo sembra funzionare bene. Grazie a Berislav per l'idea originale!
if name in ALLOWABLE_VALUES: ...
'val' in ('val_first', 'second_val',)
stia chiedendo: non c'è False
nessun problema di sottostringa qui.
if
dichiarazione? voglio controllare il DEBUG
valore
Ho migliorato un po ' la risposta di chrisdew (per creare il tuo tag).
Innanzitutto, crea il file yourapp/templatetags/value_from_settings.py
in cui definisci il tuo nuovo 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
Puoi utilizzare questo tag nel tuo modello tramite:
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" %}
o via
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" as my_fqdn %}
Il vantaggio della as ...
notazione è che questo lo rende facile da usare in blocktrans
blocchi tramite un semplice {{my_fqdn}}
.
Aggiunta di una risposta con istruzioni complete per la creazione di un tag modello personalizzato che risolva questo problema con Django 2.0+
Nella cartella dell'app, crea una cartella denominata templatetags . In esso, crea __init__.py e custom_tags.py :
In custom_tags.py crea una funzione tag personalizzata che fornisce l'accesso a una chiave arbitraria nella costante delle impostazioni :
from django import template
from django.conf import settings
register = template.Library()
@register.simple_tag
def get_setting(name):
return getattr(settings, name, "")
Per capire questo codice ti consiglio di leggere la sezione sui semplici tag nei documenti Django.
Quindi, devi rendere Django consapevole di questo (e di ogni altro tag) personalizzato caricando questo file in qualsiasi modello in cui lo utilizzerai. Proprio come è necessario caricare il tag statico incorporato:
{% load custom_tags %}
Una volta caricato, può essere utilizzato come qualsiasi altro tag, basta fornire l'impostazione specifica che è necessario restituire. Quindi se hai una variabile BUILD_VERSION nelle tue impostazioni:
{% get_setting "BUILD_VERSION" %}
Questa soluzione non funzionerà con le matrici, ma se è necessario è possibile che si stia mettendo molta logica nei modelli.
Nota: una soluzione più pulita e in sicurezza sarebbe probabilmente quella di rendere un processore di contesto personalizzato in cui aggiungere le impostazioni necessarie a un contesto disponibile per tutti i modelli. In questo modo si riduce il rischio di emettere per errore impostazioni sensibili nei modelli.
Aggiungi questo codice a un file chiamato context_processors.py
:
from django.conf import settings as django_settings
def settings(request):
return {
'settings': django_settings,
}
Quindi, nel file delle impostazioni, includi un percorso come 'speedy.core.base.context_processors.settings'
(con il nome e il percorso dell'app) nelle 'context_processors'
impostazioni in TEMPLATES
.
(Puoi vedere ad esempio settings / base.py e context_processors.py ).
Quindi è possibile utilizzare l'impostazione specifica in qualsiasi codice modello. Per esempio:
{% if settings.SITE_ID == settings.SPEEDY_MATCH_SITE_ID %}
Aggiornamento: il codice sopra espone tutte le impostazioni ai modelli, comprese le informazioni sensibili come la tua SECRET_KEY
. Un hacker potrebbe abusare di questa funzione per visualizzare tali informazioni nei modelli. Se si desidera esporre solo le impostazioni specifiche ai modelli, utilizzare invece questo codice:
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
. Un hacker potrebbe abusare di questa funzione per visualizzare tali informazioni nei modelli.
L'esempio sopra riportato da bchhun è utile, tranne per il fatto che è necessario creare esplicitamente il dizionario di contesto da settings.py. Di seguito è riportato un esempio UNTESTED di come è possibile creare automaticamente il dizionario di contesto da tutti gli attributi maiuscoli di settings.py (re: "^ [A-Z0-9 _] + $").
Alla fine di 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 qualcuno trova questa domanda come ho fatto io, posterò la mia soluzione che funziona su Django 2.0:
Questo tag assegna alcuni valori della variabile settings.py alla variabile del modello:
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 %}
Consulta la documentazione di Django su come creare tag modello personalizzati qui: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/
{% if settings_debug %}
{% if settings_debug == True %}
al tuo suggerito{% if settings_debug %}
Se si utilizza una vista basata su classi:
#
# 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 }}
Sia IanSR che bchhun hanno suggerito di sostituire TEMPLATE_CONTEXT_PROCESSORS nelle impostazioni. Tenere presente che questa impostazione ha un valore predefinito che può causare alcune cose errate se si esegue l'override senza ripristinare le impostazioni predefinite. Le impostazioni predefinite sono cambiate anche nelle ultime versioni di Django.
https://docs.djangoproject.com/en/1.3/ref/settings/#template-context-processors
Il TEMPLATE_CONTEXT_PROCESSORS predefinito:
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 dovessimo confrontare i tag di contesto e di modello su una singola variabile, allora conoscere l'opzione più efficiente potrebbe essere positivo. Tuttavia, potrebbe essere meglio immergersi nelle impostazioni solo dai modelli che richiedono quella variabile. In tal caso, non ha senso passare la variabile in tutti i modelli. Ma se stai inviando la variabile in un modello comune come il modello base.html, non importa se il modello base.html viene visualizzato su ogni richiesta, quindi puoi utilizzare entrambi i metodi.
Se decidi di utilizzare l'opzione tag modello, utilizza il seguente codice in quanto ti consente di passare un valore predefinito , nel caso in cui la variabile in questione non fosse definita.
Esempio: get_from_settings my_variable come my_context_value
Esempio: get_from_settings my_variable my_default come 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)