web-dev-qa-db-fra.com

Puis-je accéder aux constantes dans settings.py à partir de modèles dans Django?

Il y a quelques éléments dans settings.py auxquels j'aimerais pouvoir accéder à partir d'un modèle, mais je ne vois pas comment le faire. J'ai déjà essayé

{{CONSTANT_NAME}}

mais cela ne semble pas fonctionner. Est-ce possible?

342
Paul Wicks

Django fournit un accès à certaines constantes de paramètres fréquemment utilisées pour le modèle, telles que settings.MEDIA_URL et à certains paramètres de langue si vous utilisez les vues génériques intégrées de Django ou si vous transmettez un argument de mot clé d'instance de contexte dans le 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 disposeront de plusieurs paramètres fréquemment utilisés, tels que settings.MEDIA_URL disponible pour le modèle en tant que {{ MEDIA_URL }}, etc.

Si vous recherchez un accès à d'autres constantes dans les paramètres, décompressez-les simplement et ajoutez-les au dictionnaire de contexte que vous utilisez dans votre fonction d'affichage, comme suit:

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)

Vous pouvez maintenant accéder à settings.FAVORITE_COLOR sur votre modèle en tant que {{ favorite_color }}.

166
Prairiedogg

Si c'est une valeur que vous aimeriez avoir pour chaque requête et modèle, utiliser un processeur de contexte est plus approprié.

Voici comment:

  1. Créez un fichier context_processors.py dans votre répertoire app. Disons que je veux avoir la valeur ADMIN_PREFIX_VALUE dans chaque contexte:

    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}
    
  2. 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",
            ],
        }
    }]
    
  3. Utilisez RequestContext dans votre vue pour ajouter vos processeurs de contexte dans votre modèle. Le raccourci render effectue automatiquement cette opération:

    from Django.shortcuts import render
    
    def my_view(request):
        return render(request, "index.html")
    
  4. et enfin, dans votre modèle:

    ...
    <a href="{{ ADMIN_MEDIA_URL }}">path to admin media</a>
    ...
    
409
bchhun

Je trouve que l'approche la plus simple consiste à utiliser une seule balise de modèle:

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" %}
240
Berislav Lopac

Départ Django-settings-export (disclaimer: je suis l'auteur de ce projet).

Par exemple...

_$ 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>
_
89
Jakub

Pour ce faire, vous pouvez également créer une balise de modèle personnalisée qui peut vous permettre d'extraire des valeurs 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 traitement de contexte.

42
fadedbee

J'aime la solution de Berislav, car sur des sites simples, elle est propre et efficace. Ce que je n'aime PAS, c'est d'exposer toutes les constantes des paramètres, bon gré mal gré. Donc ce que j'ai fini par faire était 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 d'utiliser dans le modèle. Si vous voulez vraiment avoir du style, vous pouvez définir un Tuple dans les paramètres, créer plusieurs balises de modèle pour différentes pages, applications ou zones, et simplement combinez un Tuple local avec les paramètres Tuple selon vos besoins, puis faites 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 existe des valeurs qu’il serait agréable d’avoir universellement dans les modèles, et cela semble bien fonctionner. Merci à Berislav pour l'idée originale!

24
MontyThreeCard

J'ai amélioré la réponse de chrisdew (pour créer votre propre tag) un peu.

Commencez par créer le fichier yourapp/templatetags/value_from_settings.py dans lequel vous définissez votre 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 notation as ... est qu'elle facilite l'utilisation dans les blocs blocktrans via un simple {{my_fqdn}}.

11
pklaus

Ajout d'une réponse avec des instructions complètes pour la création d'une balise de modèle personnalisée permettant de résoudre ce problème, avec Django 2.0 +

Dans votre dossier d'application, créez un dossier appelé templatetags . Dans ce document, créez __ init __. Py et custom_tags.py :

Custom tags folder structure

Dans le custom_tags.py , créez une fonction de balise personnalisée donnant accès à une clé arbitraire dans les paramètres . constant:

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 vous 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 tout modèle où vous l'utiliserez. Tout comme vous devez charger la balise statique intégrée:

{% load custom_tags %}

Avec celui-ci chargé, il peut être utilisé comme n'importe quelle autre balise, il vous suffit de fournir le paramètre spécifique que vous souhaitez retourner. 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 beaucoup de logique dans vos modèles.

9
Andreas Bergström

L'exemple ci-dessus de bchhun est Nice, sauf que vous devez explicitement créer votre dictionnaire de contexte à partir de settings.py. Vous trouverez ci-dessous un exemple UNTESTED sur la manière de construire automatiquement le dictionnaire de contexte à partir de tous les attributs 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',
...
)
7
IanSR

Si quelqu'un trouve cette question comme moi, alors je posterai ma solution qui fonctionne sur Django 2.0:

Cette balise affecte une valeur de variable settings.py à la variable de template:

Utilisation: {% 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)

Votre template:

{% 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 sur la création de balises de modèle personnalisées ici: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/

5
NullIsNot0

Ajoutez ce code à un fichier nommé context_processors.py:

from Django.conf import settings as Django_settings


def settings(request):
    return {
        'settings': Django_settings,
    }

Ensuite, 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 paramètres 'context_processors' de TEMPLATES.

(Vous pouvez voir par exemple https://github.com/speedy-net/speedy-net/blob/staging/speedy/core/settings/base.py et https://github.com/speedy-net/speedy-net/blob/staging/speedy/core/base/context_processors.py ).

4
Uri

Si vous utilisez une vue basée sur les classes:

#
# 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 }}
4
Bill Paetzke

J'ai trouvé que c'était l'approche la plus simple pour Django 1.3:

  1. views.py

    from local_settings import BASE_URL
    
    def root(request):
        return render_to_response('hero.html', {'BASE_URL': BASE_URL})
    
  2. hero.html

    var BASE_URL = '{{ JS_BASE_URL }}';
    
1
Michael

IanSR et bchhun ont tous deux suggéré de remplacer TEMPLATE_CONTEXT_PROCESSORS dans les paramètres. Sachez que ce paramètre a une valeur par défaut qui peut causer des problèmes si vous l’écrivez sans redéfinir les valeurs par défaut. Les valeurs par défaut ont également changé dans les versions récentes de Django.

https://docs.djangoproject.com/fr/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")
0
MrOodles

Si nous comparions les balises de contexte et de modèle avec une seule variable, il serait bénéfique de connaître l'option la plus efficace. Cependant, il serait peut-être préférable de puiser dans les paramètres uniquement à partir de modèles qui ont besoin de cette variable. Dans ce cas, il n’a aucun sens de transmettre la variable à tous les modèles. Mais si vous envoyez la variable dans un modèle commun, tel que le modèle base.html, le fait que le modèle base.html soit restitué à chaque demande importera peu, de sorte que vous pouvez utiliser l'une ou l'autre des méthodes.

Si vous décidez d'utiliser l'option de modèle de balises, utilisez le code suivant, car il vous permet de passer une valeur par défaut, juste au cas où la variable en question était indéfinie.

Exemple: get_from_settings my_variable as my_context_value

Exemple: get_from_settings my_variable my_default en tant que 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)
0
un33k