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


367

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?


Si vous cherchez comment passer un paramètre à chaque réponse, regardez la réponse de bchunn sur les processeurs de contexte
Zags

1
La réponse de @jkbrzt est une solution pré-packagée qui résout ce problème rapidement et facilement. Les futurs lecteurs devraient jeter un œil à ce stackoverflow.com/a/25841039/396005 par rapport à la réponse acceptée
Bron Davies

Réponses:


183

Django fournit un accès à certaines constantes de paramètres fréquemment utilisées du modèle, telles que settings.MEDIA_URLcertains 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_responsefonction 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_URLdisponibles 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 }}.


66
Il convient de noter que les valeurs spécifiques ajoutées à l'aide d'un RequestContext dépendent de la valeur de TEMPLATE_CONTEXT_PROCESSORS. Ainsi, si vous souhaitez que des valeurs supplémentaires soient transmises partout, écrivez simplement votre propre processeur de contexte et ajoutez-le à TEMPLATE_CONTEXT_PROCESSORS.
Carl Meyer

Un point sur la cohérence, dans les vues génériques, et dans de nombreuses applications de base et contrib, le contexte supplémentaire est appelé extra_context, et très souvent il est inclus dans les arguments de la vue.
Soviut

"Django donne accès à certaines constantes de paramètres fréquemment utilisées du modèle, telles que settings.MEDIA_URL". Cela ne semble pas fonctionner dans Django 1.3, bien que je l'utilise probablement mal. Existe-t-il une documentation pour cette fonctionnalité?
SystemParadox

1
@asofyan oui, ajoutez créer un processeur de contexte de modèle personnalisé et ajoutez-le à TEMPLATE_CONTEXT_PROCESSORS dans settings.py.
Paolo

14
Regardez django-settings-exportpour éviter d'avoir à écrire ce code dans chaque vue.
qris

441

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:

  1. Créez un context_processors.pyfichier dans le répertoire de votre application. Disons que je veux avoir la ADMIN_PREFIX_VALUEvaleur 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}
    
  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à votre avis pour ajouter vos processeurs de contexte dans votre modèle. Le renderraccourci le fait automatiquement:

    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>
    ...
    

32
@MarkEssel Ces cercles sont créés de manière à ce que la variable soit accessible dans toutes les vues que vous créez tant qu'elle utilise la fonction RequestContext. Vous pouvez toujours récupérer une variable de paramètres manuellement dans chaque vue. Je choisirais un processeur de contexte réutilisable à tout moment au lieu d'un bon vieux copier-coller.
bchhun

5
faire de mon mieux pour éviter de copier / coller partout possible. chaque application (au sein d'un projet) aurait-elle besoin d'un context_processor.py, existe-t-il un moyen de construire un context_processor pour chacune d'entre elles?
Mark Essel

10
@bchhun Je viens de tester (Django 1.3): le partage d'un processeur de contexte entre les applications fonctionne très bien. :-) J'ai mis context_process.pyjuste à côté de mon settings.pydossier et ajouté "context_processors.admin_media"à ma TEMPLATE_CONTEXT_PROCESSORSliste. 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.
MiniQuark

5
@MarkEssel Pas du tout douloureux - il vient de tout expliquer. Ce n'est vraiment que 6 lignes courtes (étapes 1 et 2). Les étapes 3 et 4 ou leur équivalent sont de toute façon nécessaires pour la plupart des modèles.
Rick Westera

2
Depuis Django 1.3, vous pouvez utiliser le renderraccourci pour éviter d'avoir à inclure explicitement RequestContext
yndolok

269

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" %}

17
J'adore avoir accès à la demande à n'importe quel paramètre dans les modèles, et cela offre cela avec élégance. C'est vraiment beaucoup mieux que les autres réponses si vous utilisez fréquemment divers paramètres dans vos modèles: 1) La réponse acceptée est incompatible ou maladroite avec les vues basées sur la classe. 2) Avec la solution de processeur de contexte de modèle trop voté, vous devez spécifier des paramètres individuels (ou tous) et cela s'exécuterait pour chaque demande unique qui rend un modèle - inefficace! 3) C'est plus simple que la balise plus complexe ci-dessus.
Ben Roberts

16
@BenRoberts Je suis d'accord pour dire que c'est une solution élégante ... mais seulement pour de petits projets avec un seul développeur qui fait tout. Si vous avez des personnes / équipes distinctes pour la conception et le développement, cette solution est probablement la pire . Qu'est-ce qui empêche le concepteur d'abuser de cette balise avec quelque chose comme {% settings_value "DATABASES" %}:? Ce cas d'utilisation devrait rendre évident pourquoi les paramètres ne sont pas disponibles dans les modèles pour commencer.
mkoistinen

23
"Nous sommes tous des adultes consentants ici"
frnhr

11
Pardonnez-moi d'être un débutant. Où mettez-vous ce code? Views.py? Ou sur un nouveau fichier?
Noel Llevares

13
pour être clair pour les autres, vous devez: 1) créer un templatetagsdossier dans votre application avec un __init__.pyfichier vide et ce code comme settings.pydans ce dossier. 2) dans votre modèle, vous ajoutez {% load settings %}puis utilisez votre nouvelle balise!
damio

95

Check out django-settings-export(avertissement: 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>

1
Et notez que selon vous, vous devez utiliser renderet nonrender_to_response
Everett Toews

J'ai une exigence similaire de lire les valeurs de la configuration dans les modèles, mais j'obtiens une erreur de 500 lorsque j'ajoute 'django_settings_export.settings_export' dans le fichier de configuration.Pouvez-vous suggérer ce que je fais de mal ici
Piyush Sahu

3
Nous sommes en 2019 et je l'utilise dans mon projet. Merci!
sivabudh

1
Je suis d'accord avec @sivabudh. C'est aussi pour moi la meilleure solution car 1. Il est centralisé ce qui signifie que je n'ai pas besoin de dossier et de fichiers supplémentaires, 2. Je peux voir l'espace de noms des paramètres dans mon modèle qui est très utile pour obtenir les références de nombreuses applications.
ywiyogo

46

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.


6
je pense que c'est la solution la plus élégante, car elle fonctionne comme dropin sans changer le code.
vol de moutons

1
que vous pouvez laisser le reste de votre application inchangé: vous ajoutez une balise et l'utilisez, au lieu d'avoir à ajouter des processeurs de contexte (ce qui signifie que vous devez modifier votre application à plusieurs endroits)
flying

2
@Mark - dans produi / src / produi / template_utils / templatetags / custom_template_filters.py template_utils est référencé à partir de settings.py INSTALLED_APPS - voir aussi docs.djangoproject.com/en/dev/howto/custom-template-tags
fadedbee

appréciez l'aide chris, a ajouté une application mutil avec un sous-répertoire templatetags comprenant custom_template_filters. Toujours obtenir une erreur dans homepage.html "Balise de bloc non valide: 'value_from_settings', 'endblock' ou 'endblock banner' attendu" "
Mark Essel

Je pense que cela va à l'encontre "explicite vaut mieux qu'implicite", en utilisant la version du décorateur de contexte, vous choisissez exactement les paramètres à exposer.
2012

29

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!


5
pourquoi pas simplementif name in ALLOWABLE_VALUES: ...
frnhr

Parce que je pensais que j'étais intelligent, et je voulais empêcher les sous-chaînes de déclencher les paramètres var. ;-) Le retour devrait probablement être: return getattr (settings, is_allowable, '')
MontyThreeCard

5
Juste pour clarifier pour tous ceux qui se demande: 'val' in ('val_first', 'second_val',)est False, sousChaîne aucun problème ici.
2014

2
Comment puis-je utiliser cela dans la ifdéclaration? je veux vérifier la DEBUGvaleur
AJ

Si quelqu'un avait besoin d'une version avec re inclus gist.github.com/BrnoPCmaniak/632f56ddb907108b3d43fa862510dfca
Filip Dobrovolný

12

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.pydans 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 blocktransblocs via un simple {{my_fqdn}}.


12

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 :

Structure de dossier de balises personnalisées

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.


9

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,
    }

1
J'ai rencontré ce problème hier, j'ai trouvé cet article, puis 2 autres et un article de blog et j'ai estimé que chacun d'entre eux était bien trop compliqué (malheureusement, je ne suis pas allé aussi loin en bas de la page, honte à moi). Alors j'ai fini par rouler le mien, ce qui est EXACTEMENT cette solution. Je reviens juste parce que ça me dérangeait que les gens recommandent des plugins et tout un code lotta quand cette fonction 3 lignes et le changement 1 ligne dans settings.py.
DXM

@DXM Merci!
Speedy Match

En fait, ma solution expose tous les paramètres aux modèles, y compris les informations sensibles telles que SECRET_KEY. Un pirate pourrait abuser de cette fonctionnalité pour afficher une telle information dans les modèles.
Speedy Match

J'ai mis à jour ma réponse.
Speedy Match

eh bien ... super, maintenant mon site Web a le même problème :) Mais ... il me manque peut-être quelque chose, cependant, sommes-nous sûrs qu'il y a un problème? Les modèles sont essentiellement les mêmes que le code source de votre site Web, n'est-ce pas? Ils sont stockés côté serveur et inaccessibles directement depuis le front-end. Si un pirate peut modifier un modèle, à ce stade, il peut modifier n'importe quel fichier .py.
DXM

8

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',
...
)

8

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" %}

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 modèle:

{% 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/


1
{% if settings_debug %}
user66081

Merci @ user66081! Modifié {% if settings_debug == True %}à votre suggestion{% if settings_debug %}
NullIsNot0

7

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 }}

3

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

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")

1

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)

Ou vous pouvez utiliser SITE_EXTRA_CONTEXT_DICTdans le logiciel final pour le faire pour vous.
un33k
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.