Comment obtenir le nom de domaine de mon site actuel à partir d'un modèle Django? J'ai essayé de regarder dans la balise et les filtres mais rien là-bas.
Comment obtenir le nom de domaine de mon site actuel à partir d'un modèle Django? J'ai essayé de regarder dans la balise et les filtres mais rien là-bas.
Réponses:
Je pense que ce que vous voulez, c'est avoir accès au contexte de la demande, voir RequestContext.
Host:
tête et obtient une réponse avec le domaine usurpé quelque part sur une page, comment cela crée-t-il une faille de sécurité? Je ne vois pas en quoi cela diffère d'un utilisateur prenant le HTML généré et se modifiant avant de le nourrir dans son propre navigateur.
Si vous voulez l'en-tête HTTP Host réel, consultez le commentaire de Daniel Roseman sur la réponse de @ Phsiao. L'autre alternative est que si vous utilisez le framework contrib.sites , vous pouvez définir un nom de domaine canonique pour un site dans la base de données (mapper le domaine de requête à un fichier de paramètres avec le SITE_ID approprié est quelque chose que vous devez faire vous-même via votre configuration du serveur Web). Dans ce cas, vous recherchez:
from django.contrib.sites.models import Site
current_site = Site.objects.get_current()
current_site.domain
vous devrez placer vous-même l'objet current_site dans un contexte de modèle si vous souhaitez l'utiliser. Si vous l'utilisez partout, vous pouvez l'empaqueter dans un processeur de contexte de modèle.
SITE_ID
paramètre est égal à l' id
attribut du site actuel dans l'application Sites (vous pouvez le trouver id
dans le panneau d'administration de Sites). Lorsque vous appelez get_current
, Django prend votre SITE_ID
et renvoie l' Site
objet avec cet identifiant de la base de données.
print("get_current_site: ", get_current_site(request)) print("absolute uri: ", request.build_absolute_uri()) print("HTTP_HOST: ", request.META['HTTP_HOST']) get_current_site: localhost:8001 absolute uri: http://localhost:8001/... HTTP_HOST: localhost:8001
J'ai découvert la {{ request.get_host }}
méthode.
HTTP_X_FORWARDED_HOST
en-tête HTTP.
request.build_absolute_uri
( docs.djangoproject.com/en/dev/ref/request-response/… )
En complément de Carl Meyer, vous pouvez créer un processeur de contexte comme celui-ci:
from django.conf import settings
def site(request):
return {'SITE_URL': settings.SITE_URL}
SITE_URL = 'http://google.com' # this will reduce the Sites framework db call.
TEMPLATE_CONTEXT_PROCESSORS = (
...
"module.context_processors.site",
....
)
vous pouvez écrire votre propre rutine si vous souhaitez gérer des sous-domaines ou SSL dans le processeur de contexte.
La variante du processeur de contexte que j'utilise est:
from django.contrib.sites.shortcuts import get_current_site
from django.utils.functional import SimpleLazyObject
def site(request):
return {
'site': SimpleLazyObject(lambda: get_current_site(request)),
}
L' SimpleLazyObject
encapsuleur garantit que l'appel de base de données se produit uniquement lorsque le modèle utilise réellement l' site
objet. Cela supprime la requête des pages d'administration. Il met également en cache le résultat.
et incluez-le dans les paramètres:
TEMPLATE_CONTEXT_PROCESSORS = (
...
"module.context_processors.site",
....
)
Dans le modèle, vous pouvez utiliser {{ site.domain }}
pour obtenir le nom de domaine actuel.
edit: pour prendre en charge également la commutation de protocole, utilisez:
def site(request):
site = SimpleLazyObject(lambda: get_current_site(request))
protocol = 'https' if request.is_secure() else 'http'
return {
'site': site,
'site_root': SimpleLazyObject(lambda: "{0}://{1}".format(protocol, site.domain)),
}
SimpleLazyObject
ici, car le lambda ne sera pas appelé si rien n'accède de toute façon au «site».
SimpleLazyObject
, chacun RequestContext
appellera get_current_site()
et exécutera donc une requête SQL. L'encapsuleur s'assure que la variable n'est évaluée que lorsqu'elle est réellement utilisée dans le modèle.
SimpleLazyObject
est là pour éviter la réévaluation de la fonction, ce qui n'est pas vraiment nécessaire puisque l' Site
objet est mis en cache.
from django.contrib.sites.shortcuts import get_current_site
Je sais que cette question est ancienne, mais je suis tombée dessus à la recherche d'un moyen pythonique pour obtenir le domaine actuel.
def myview(request):
domain = request.build_absolute_uri('/')[:-1]
# that will build the complete domain: http://foobar.com
build_absolute_uri
est documenté ici .
Rapide et simple, mais pas bon pour la production:
(dans une vue)
request.scheme # http or https
request.META['HTTP_HOST'] # example.com
request.path # /some/content/1/
(dans un modèle)
{{ request.scheme }} :// {{ request.META.HTTP_HOST }} {{ request.path }}
Assurez-vous d'utiliser un RequestContext , ce qui est le cas si vous utilisez render .
Ne faites pas confiance request.META['HTTP_HOST']
à la production: ces informations proviennent du navigateur. Utilisez plutôt la réponse de @ CarlMeyer
request.scheme
. Peut-être uniquement disponible dans les versions plus récentes de django.
request.scheme
été ajouté dans Django 1.7.
{{ request.get_host }}
doit protéger contre les attaques d'en-tête HTTP Host lorsqu'il est utilisé avec le ALLOWED_HOSTS
paramètre (ajouté dans Django 1.4.4).
Notez que {{ request.META.HTTP_HOST }}
n'a pas la même protection. Voir la documentation :
ALLOWED_HOSTS
Une liste de chaînes représentant les noms d'hôte / de domaine que ce site Django peut servir. Il s'agit d'une mesure de sécurité pour empêcher les attaques d'en-tête HTTP Host , qui sont possibles même dans de nombreuses configurations de serveur Web apparemment sûres.
... Si l'en-
Host
tête (ouX-Forwarded-Host
s'ilUSE_X_FORWARDED_HOST
est activé) ne correspond à aucune valeur de cette liste, ladjango.http.HttpRequest.get_host()
méthode augmenteraSuspiciousOperation
.... Cette validation s'applique uniquement via
get_host()
; si votre code accède à l'en-tête Host directement à partir derequest.META
vous, vous contournez cette protection de sécurité.
En ce qui concerne l'utilisation de request
dans votre modèle, les appels de la fonction de rendu de modèle ont changé dans Django 1.8 , vous n'avez donc plus à gérer RequestContext
directement.
Voici comment rendre un modèle pour une vue, à l'aide de la fonction de raccourci render()
:
from django.shortcuts import render
def my_view(request):
...
return render(request, 'my_template.html', context)
Voici comment rendre un modèle pour un e-mail, lequel IMO est le cas le plus courant où vous souhaitez la valeur d'hôte:
from django.template.loader import render_to_string
def my_view(request):
...
email_body = render_to_string(
'my_template.txt', context, request=request)
Voici un exemple d'ajout d'une URL complète dans un modèle d'e-mail; request.scheme devrait obtenir http
ou https
selon ce que vous utilisez:
Thanks for registering! Here's your activation link:
{{ request.scheme }}://{{ request.get_host }}{% url 'registration_activate' activation_key %}
J'utilise une balise de modèle personnalisée. Ajouter à par exemple <your_app>/templatetags/site.py
:
# -*- coding: utf-8 -*-
from django import template
from django.contrib.sites.models import Site
register = template.Library()
@register.simple_tag
def current_domain():
return 'http://%s' % Site.objects.get_current().domain
Utilisez-le dans un modèle comme celui-ci:
{% load site %}
{% current_domain %}
get_current
est une méthode documentée: docs.djangoproject.com/en/dev/ref/contrib/sites/…
'http://%s'
pourrait être un problème en cas de https
connexion; schéma n'est pas dynamique dans ce cas.
Semblable à la réponse de l'utilisateur panchicore, c'est ce que j'ai fait sur un site Web très simple. Il fournit quelques variables et les rend disponibles sur le modèle.
SITE_URL
tiendrait une valeur comme example.com
SITE_PROTOCOL
tiendrait une valeur comme http
ou https
SITE_PROTOCOL_URL
contiendrait une valeur comme http://example.com
ou https://example.com
SITE_PROTOCOL_RELATIVE_URL
tiendrait une valeur comme //example.com
.
module / context_processors.py
from django.conf import settings
def site(request):
SITE_PROTOCOL_RELATIVE_URL = '//' + settings.SITE_URL
SITE_PROTOCOL = 'http'
if request.is_secure():
SITE_PROTOCOL = 'https'
SITE_PROTOCOL_URL = SITE_PROTOCOL + '://' + settings.SITE_URL
return {
'SITE_URL': settings.SITE_URL,
'SITE_PROTOCOL': SITE_PROTOCOL,
'SITE_PROTOCOL_URL': SITE_PROTOCOL_URL,
'SITE_PROTOCOL_RELATIVE_URL': SITE_PROTOCOL_RELATIVE_URL
}
settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
...
"module.context_processors.site",
....
)
SITE_URL = 'example.com'
Ensuite, sur vos modèles, les utiliser comme {{ SITE_URL }}
, {{ SITE_PROTOCOL }}
, {{ SITE_PROTOCOL_URL }}
et{{ SITE_PROTOCOL_RELATIVE_URL }}
Dans un modèle Django, vous pouvez faire:
<a href="{{ request.scheme }}://{{ request.META.HTTP_HOST }}{{ request.path }}?{{ request.GET.urlencode }}" >link</a>
django.template.context_processors.request
aussi [ce guide a aidé] ( simpleisbetterthancomplex.com/tips/2016/07/20/… )
Si vous utilisez le processeur de contexte "request" , et que vous utilisez le framework de sites Django et que le middleware du site est installé (c'est-à-dire que vos paramètres les incluent):
INSTALLED_APPS = [
...
"django.contrib.sites",
...
]
MIDDLEWARE = [
...
"django.contrib.sites.middleware.CurrentSiteMiddleware",
...
]
TEMPLATES = [
{
...
"OPTIONS": {
"context_processors": [
...
"django.template.context_processors.request",
...
]
}
}
]
... alors vous aurez l' request
objet disponible dans des modèles, et il contiendra une référence au courant Site
pour la demande sous forme de request.site
. Vous pouvez ensuite récupérer le domaine dans un modèle avec:
{{request.site.domain}}
Et cette approche? Travaille pour moi. Il est également utilisé dans django-registration .
def get_request_root_url(self):
scheme = 'https' if self.request.is_secure() else 'http'
site = get_current_site(self.request)
return '%s://%s' % (scheme, site)
localhost
vous donnera un https
schéma (il est considéré comme sécurisé) qui ne fonctionnera pas si vous avez une URL statique (seule http://127.0.0.1
est valide, non https://127.0.0.1
). Ce n'est donc pas idéal quand il est encore en développement.
from django.contrib.sites.models import Site
if Site._meta.installed:
site = Site.objects.get_current()
else:
site = RequestSite(request)
Vous pouvez utiliser {{ protocol }}://{{ domain }}
dans vos modèles pour obtenir votre nom de domaine.
request.META['HTTP_HOST']
vous donne le domaine. Dans un modèle, ce serait{{ request.META.HTTP_HOST }}
.