J'ai des éléments dans settings.py auxquels j'aimerais pouvoir accéder à partir d'un modèle, mais je ne sais pas comment le faire. J'ai déjà essayé
{{CONSTANT_NAME}}
mais cela ne semble pas fonctionner. Est-ce possible?
J'ai des éléments dans settings.py auxquels j'aimerais pouvoir accéder à partir d'un modèle, mais je ne sais pas comment le faire. J'ai déjà essayé
{{CONSTANT_NAME}}
mais cela ne semble pas fonctionner. Est-ce possible?
Réponses:
Django fournit un accès à certaines constantes de paramètres fréquemment utilisées du modèle, telles que settings.MEDIA_URL
certains des paramètres de langue, si vous utilisez les vues génériques intégrées de django ou passez un argument de mot-clé d'instance de contexte dans la render_to_response
fonction de raccourci. Voici un exemple de chaque cas:
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))
Ces vues auront toutes deux plusieurs paramètres fréquemment utilisés comme settings.MEDIA_URL
disponibles pour le modèle en tant que {{ MEDIA_URL }}
, etc.
Si vous recherchez l'accès à d'autres constantes dans les paramètres, décompressez simplement les constantes que vous souhaitez et ajoutez-les au dictionnaire de contexte que vous utilisez dans votre fonction d'affichage, comme ceci:
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)
Maintenant, vous pouvez accéder settings.FAVORITE_COLOR
à votre modèle en tant que {{ favorite_color }}
.
django-settings-export
pour éviter d'avoir à écrire ce code dans chaque vue.
Si c'est une valeur que vous souhaitez avoir pour chaque demande et modèle, l'utilisation d'un processeur de contexte est plus appropriée.
Voici comment:
Créez un context_processors.py
fichier dans le répertoire de votre application. Disons que je veux avoir la ADMIN_PREFIX_VALUE
valeur dans tous les contextes:
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}
ajoutez votre processeur de contexte à votre fichier settings.py :
TEMPLATES = [{
# whatever comes before
'OPTIONS': {
'context_processors': [
# whatever comes before
"your_app.context_processors.admin_media",
],
}
}]
Utilisez RequestContext
à votre avis pour ajouter vos processeurs de contexte dans votre modèle. Le render
raccourci le fait automatiquement:
from django.shortcuts import render
def my_view(request):
return render(request, "index.html")
et enfin, dans votre modèle:
...
<a href="{{ ADMIN_MEDIA_URL }}">path to admin media</a>
...
context_process.py
juste à côté de mon settings.py
dossier et ajouté "context_processors.admin_media"
à ma TEMPLATE_CONTEXT_PROCESSORS
liste. En outre, vous souhaiterez peut-être ajouter une note dans votre réponse sur le fait que la valeur par défaut de TEMPLATE_CONTEXT_PROCESSORS n'est pas vide, donc si un code existant utilise l'une des valeurs définies par ces processeurs de contexte par défaut, ils ne fonctionneront pas sauf si vous les ajoutez à nouveau à la liste explicitement.
render
raccourci pour éviter d'avoir à inclure explicitement RequestContext
Je trouve l'approche la plus simple étant une seule balise de modèle personnalisée :
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, "")
Usage:
{% settings_value "LANGUAGE_CODE" %}
{% settings_value "DATABASES" %}
:? Ce cas d'utilisation devrait rendre évident pourquoi les paramètres ne sont pas disponibles dans les modèles pour commencer.
templatetags
dossier dans votre application avec un __init__.py
fichier vide et ce code comme settings.py
dans ce dossier. 2) dans votre modèle, vous ajoutez {% load settings %}
puis utilisez votre nouvelle balise!
Check out django-settings-export
(avertissement: je suis l'auteur de ce projet).
Par exemple...
$ 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
et nonrender_to_response
Une autre façon de procéder consiste à créer une balise de modèle personnalisée qui peut vous permettre de pêcher des valeurs hors des paramètres.
@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))
Vous pouvez ensuite utiliser:
{% value_from_settings "FQDN" %}
pour l'imprimer sur n'importe quelle page, sans passer par des cercles de processeur de contexte.
J'aime la solution de Berislav, car sur des sites simples, elle est propre et efficace. Ce que je n'aime pas, c'est exposer toutes les constantes de paramètres à volonté. Donc ce que j'ai fini par faire, c'est ceci:
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 ''
Usage:
{% settings_value "CONSTANT_NAME_1" %}
Cela protège toutes les constantes que vous n'avez pas nommées de l'utilisation dans le modèle, et si vous vouliez vraiment devenir fantaisiste, vous pouvez définir un tuple dans les paramètres et créer plus d'une balise de modèle pour différentes pages, applications ou zones, et simplement combiner un tuple local avec le tuple de paramètres selon les besoins, puis faire la compréhension de la liste pour voir si la valeur est acceptable.
Je suis d'accord, sur un site complexe, c'est un peu simpliste, mais il y a des valeurs qui seraient bien d'avoir universellement dans les modèles, et cela semble bien fonctionner. Merci à Berislav pour l'idée originale!
if name in ALLOWABLE_VALUES: ...
'val' in ('val_first', 'second_val',)
est False
, sousChaîne aucun problème ici.
if
déclaration? je veux vérifier la DEBUG
valeur
J'ai un peu amélioré la réponse de chrisdew (pour créer votre propre tag).
Créez d'abord le fichier yourapp/templatetags/value_from_settings.py
dans lequel vous définissez votre propre nouvelle balise 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
Vous pouvez utiliser cette balise dans votre modèle via:
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" %}
ou via
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" as my_fqdn %}
L'avantage de la as ...
notation est qu'elle facilite son utilisation dans les blocktrans
blocs via un simple {{my_fqdn}}
.
Ajouter une réponse avec des instructions complètes pour créer une balise de modèle personnalisée qui résout ce problème, avec Django 2.0+
Dans votre dossier d'application, créez un dossier appelé templatetags . Dans celui-ci, créez __init__.py et custom_tags.py :
Dans custom_tags.py, créez une fonction de balise personnalisée qui donne accès à une clé arbitraire dans la constante des paramètres :
from django import template
from django.conf import settings
register = template.Library()
@register.simple_tag
def get_setting(name):
return getattr(settings, name, "")
Pour comprendre ce code, je recommande de lire la section sur les balises simples dans la documentation Django.
Ensuite, vous devez informer Django de cette balise personnalisée (et de toute balise supplémentaire) en chargeant ce fichier dans n'importe quel modèle où vous l'utiliserez. Tout comme vous devez charger la balise statique intégrée:
{% load custom_tags %}
Une fois chargé, il peut être utilisé comme n'importe quelle autre balise, il suffit de fournir le paramètre spécifique que vous devez renvoyer. Donc, si vous avez une variable BUILD_VERSION dans vos paramètres:
{% get_setting "BUILD_VERSION" %}
Cette solution ne fonctionnera pas avec les tableaux, mais si vous en avez besoin, vous pourriez mettre trop de logique dans vos modèles.
Remarque: Une solution plus propre et plus sûre serait probablement de créer un processeur de contexte personnalisé dans lequel vous ajoutez les paramètres dont vous avez besoin à un contexte disponible pour tous les modèles. De cette façon, vous réduisez le risque de sortie des paramètres sensibles dans vos modèles par erreur.
Ajoutez ce code à un fichier appelé context_processors.py
:
from django.conf import settings as django_settings
def settings(request):
return {
'settings': django_settings,
}
Et puis, dans votre fichier de paramètres, incluez un chemin tel que 'speedy.core.base.context_processors.settings'
(avec le nom et le chemin de votre application) dans les 'context_processors'
paramètres de TEMPLATES
.
(Vous pouvez voir par exemple settings / base.py et context_processors.py ).
Ensuite, vous pouvez utiliser le paramètre spécifique dans n'importe quel code de modèle. Par exemple:
{% if settings.SITE_ID == settings.SPEEDY_MATCH_SITE_ID %}
Mise à jour: le code ci-dessus expose tous les paramètres aux modèles, y compris les informations sensibles telles que la vôtre SECRET_KEY
. Un pirate pourrait abuser de cette fonctionnalité pour afficher ces informations dans les modèles. Si vous souhaitez exposer uniquement des paramètres spécifiques aux modèles, utilisez plutôt ce code:
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 pirate pourrait abuser de cette fonctionnalité pour afficher une telle information dans les modèles.
L'exemple ci-dessus de bchhun est agréable, sauf que vous devez créer explicitement votre dictionnaire de contexte à partir de settings.py. Vous trouverez ci-dessous un exemple non testé de la façon dont vous pouvez créer automatiquement le dictionnaire de contexte à partir de tous les attributs en majuscules de settings.py (re: "^ [A-Z0-9 _] + $").
À la fin 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',
...
)
Si quelqu'un trouve cette question comme je l'ai fait, alors je posterai ma solution qui fonctionne sur Django 2.0:
Cette balise attribue une valeur de variable settings.py à la variable du modèle:
Usage: {% 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 %}
Voir la documentation de Django pour créer des balises de modèle personnalisées ici: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/
{% if settings_debug %}
{% if settings_debug == True %}
à votre suggestion{% if settings_debug %}
Si vous utilisez une vue basée sur une 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 et bchhun ont suggéré de remplacer TEMPLATE_CONTEXT_PROCESSORS dans les paramètres. Sachez que ce paramètre a une valeur par défaut qui peut provoquer des problèmes si vous le remplacez sans réinitialiser les valeurs par défaut. Les valeurs par défaut ont également changé dans les versions récentes de Django.
https://docs.djangoproject.com/en/1.3/ref/settings/#template-context-processors
TEMPLATE_CONTEXT_PROCESSORS par défaut:
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")
Si nous devions comparer le contexte et les balises de modèle sur une seule variable, alors connaître l'option la plus efficace pourrait être bénéfique. Cependant, il serait préférable de plonger dans les paramètres uniquement à partir de modèles qui ont besoin de cette variable. Dans ce cas, cela n'a aucun sens de passer la variable dans tous les modèles. Mais si vous envoyez la variable dans un modèle commun tel que le modèle base.html, cela n'aurait pas d'importance car le modèle base.html est rendu à chaque demande, vous pouvez donc utiliser les deux méthodes.
Si vous décidez d'utiliser l'option de balises de modèle, utilisez le code suivant car il vous permet de passer une valeur par défaut dans, juste au cas où la variable en question n'était pas définie.
Exemple: get_from_settings my_variable as my_context_value
Exemple: 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)
SITE_EXTRA_CONTEXT_DICT
dans le logiciel final pour le faire pour vous.