Wie kann ich den Domainnamen meiner Website in einer Django-Vorlage abrufen?

156

Wie erhalte ich den Domainnamen meiner aktuellen Site aus einer Django-Vorlage? Ich habe versucht, in das Tag und die Filter zu schauen, aber nichts dort.

Jean-François Fabre
quelle

Antworten:

67

Ich denke, Sie möchten Zugriff auf den Anforderungskontext haben, siehe RequestContext.

phsiao
quelle
140
request.META['HTTP_HOST']gibt Ihnen die Domain. In einer Vorlage wäre es {{ request.META.HTTP_HOST }}.
Daniel Roseman
29
Seien Sie vorsichtig bei der Verwendung von Anforderungsmetadaten. Es kommt von einem Browser und kann gefälscht werden. Im Allgemeinen möchten Sie wahrscheinlich den unten von @CarlMeyer vorgeschlagenen Vorschlägen folgen.
Josh
2
Für meine Zwecke hat dies keine Sicherheitslücke.
Paul Draper
7
Ich denke, da Django 1.5 mit den zulässigen Hosts eingestellt ist, ist es sicher zu verwenden. docs.djangoproject.com/de/1.5/ref/settings/#allowed-hosts
Daniel Backman
8
Kann jemand näher auf die "Sicherheitslücke" eingehen? Wenn der Benutzer den Host:Header fälscht und irgendwo auf einer Seite eine Antwort mit der gefälschten Domain erhält, wie entsteht dann eine Sicherheitslücke? Ich sehe nicht, wie sich das von einem Benutzer unterscheidet, der den generierten HTML-Code nimmt und sich selbst ändert, bevor er ihn seinem eigenen Browser zuführt.
user193130
104

Wenn Sie den eigentlichen HTTP-Host-Header möchten, lesen Sie Daniel Rosemans Kommentar zur Antwort von @ Phsiao. Die andere Alternative besteht darin, dass Sie bei Verwendung des Contrib.sites-Frameworks einen kanonischen Domänennamen für eine Site in der Datenbank festlegen können (das Zuordnen der Anforderungsdomäne zu einer Einstellungsdatei mit der richtigen SITE_ID müssen Sie selbst über Ihre durchführen Webserver-Setup). In diesem Fall suchen Sie:

from django.contrib.sites.models import Site

current_site = Site.objects.get_current()
current_site.domain

Sie müssten das current_site-Objekt selbst in einen Vorlagenkontext einfügen, wenn Sie es verwenden möchten. Wenn Sie es überall verwenden, können Sie es in einem Vorlagenkontextprozessor verpacken.

Carl Meyer
quelle
3
Um dies für jemanden zu klären, der die gleichen Probleme hat wie ich: Überprüfen Sie, ob Ihre SITE_IDEinstellung dem idAttribut der aktuellen Site in der Sites-App entspricht (Sie finden sie idim Sites-Admin-Bereich). Wenn Sie anrufen get_current, nimmt Django Ihre SITE_IDund gibt das SiteObjekt mit dieser ID aus der Datenbank zurück.
Dennis Golomazov
Nichts davon funktioniert für mich. 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
user251242
86

Ich habe die {{ request.get_host }}Methode entdeckt.

danbruegge
quelle
11
Bitte beachten Sie, dass diese Antwort dieselben Probleme wie der Daniel Roseman-Ansatz aufweist (sie kann gefälscht werden), aber sicherlich vollständiger ist, wenn der Host über einen HTTP-Proxy oder einen Load Balancer erreicht wird, da der HTTP_X_FORWARDED_HOSTHTTP-Header berücksichtigt wird.
Furins
4
Verwendung: "// {{request.get_host}} / irgendetwas / sonst / du / wollen" ... Geben Sie unbedingt Ihre Einstellung ALLOWED_HOSTS ein (siehe docs.djangoproject.com/de/1.5/ref/settings/#allowed) -Hosts ).
Seth
3
@ Seth besser zu verwenden request.build_absolute_uri( docs.djangoproject.com/de/dev/ref/request-response/… )
MrKsn
60

Als Ergänzung zu Carl Meyer können Sie einen Kontextprozessor wie folgt erstellen:

module.context_processors.py

from django.conf import settings

def site(request):
    return {'SITE_URL': settings.SITE_URL}

local settings.py

SITE_URL = 'http://google.com' # this will reduce the Sites framework db call.

settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
 )

Vorlagen, die eine Kontextinstanz zurückgeben. Die URL-Site lautet {{SITE_URL}}.

Sie können Ihre eigene Rutine schreiben, wenn Sie Subdomains oder SSL im Kontextprozessor verarbeiten möchten.

Panchicore
quelle
Ich habe diese Lösung ausprobiert, aber wenn Sie mehrere Subdomains für dieselbe Anwendung haben, ist dies nicht praktikabel. Ich fand die Antwort von danbruegge
Jose Luis de la Rosa
In settings.py müssen Sie Ihren Kontextprozessor unter context_processors> OPTIONS> TEMPLATES
yas17
24

Die Variation des von mir verwendeten Kontextprozessors ist:

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

Der SimpleLazyObjectWrapper stellt sicher, dass der DB-Aufruf nur dann erfolgt, wenn die Vorlage tatsächlich den verwendetsite Objekt . Dadurch wird die Abfrage von den Administrationsseiten entfernt. Es speichert auch das Ergebnis zwischen.

und in die Einstellungen aufnehmen:

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
)

In der Vorlage können Sie {{ site.domain }}den aktuellen Domainnamen abrufen.

Bearbeiten: Um auch die Protokollumschaltung zu unterstützen, verwenden Sie:

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)),
    }
vdboor
quelle
Sie müssen hier nicht verwenden SimpleLazyObject, da das Lambda nicht aufgerufen wird, wenn ohnehin nichts auf 'site' zugreift.
Monokrom
Wenn Sie das entfernen SimpleLazyObject, RequestContextruft jeder auf get_current_site()und führt daher eine SQL-Abfrage aus. Der Wrapper stellt sicher, dass die Variable nur ausgewertet wird, wenn sie tatsächlich in der Vorlage verwendet wird.
Vdboor
1
Da es sich um eine Funktion handelt, wird die Host-Zeichenfolge nur verarbeitet, wenn sie trotzdem verwendet wird. Sie können also 'site_root' einfach eine Funktion zuweisen und benötigen SimpleLazyObject nicht. Django ruft die Funktion auf, wenn sie verwendet wird. Sie haben hier ohnehin schon die notwendige Funktion mit einem Lambda angelegt.
Monokrom
Ach ja, nur ein Lambda würde funktionieren. Das SimpleLazyObjectist es Umwertung der Funktion zu vermeiden, die benötigt nicht wirklich, da das SiteObjekt zwischengespeichert wird.
Vdboor
Der Import ist jetztfrom django.contrib.sites.shortcuts import get_current_site
Hraban
22

Ich weiß, dass diese Frage alt ist, aber ich bin darauf gestoßen und habe nach einem pythonischen Weg gesucht, um die aktuelle Domain zu erhalten.

def myview(request):
    domain = request.build_absolute_uri('/')[:-1]
    # that will build the complete domain: http://foobar.com
Misterte
quelle
4
build_absolute_uriist hier dokumentiert .
Philipp Zedler
19

Schnell und einfach, aber nicht gut für die Produktion:

(in einer Ansicht)

    request.scheme               # http or https
    request.META['HTTP_HOST']    # example.com
    request.path                 # /some/content/1/

(in einer Vorlage)

{{ request.scheme }} :// {{ request.META.HTTP_HOST }} {{ request.path }}

Stellen Sie sicher, dass Sie einen RequestContext verwenden. Dies ist der Fall, wenn Sie Render verwenden .

Vertrauen Sie nicht request.META['HTTP_HOST']auf die Produktion: Diese Informationen stammen aus dem Browser. Verwenden Sie stattdessen die Antwort von @ CarlMeyer

Edward Newell
quelle
Ich stimme dieser Antwort zu, habe aber beim Versuch, sie zu verwenden, einen Fehler erhalten request.scheme. Möglicherweise nur in neueren Versionen von Django verfügbar.
Matt Cremeens
@MattCremeens request.schemewurde in Django 1.7 hinzugefügt.
S. Kirby
16

{{ request.get_host }} sollte vor HTTP-Host-Header-Angriffen schützen, wenn sie zusammen mit dem verwendet werden ALLOWED_HOSTS Einstellung verwendet werden (hinzugefügt in Django 1.4.4).

Beachten Sie, dass {{ request.META.HTTP_HOST }}dies nicht den gleichen Schutz bietet. Siehe die Dokumente :

ALLOWED_HOSTS

Eine Liste von Zeichenfolgen, die die Host- / Domänennamen darstellen, die diese Django-Site bedienen kann. Dies ist eine Sicherheitsmaßnahme, um HTTP-Host-Header-Angriffe zu verhindern , die selbst unter vielen scheinbar sicheren Webserverkonfigurationen möglich sind.

... Wenn der HostHeader (oder X-Forwarded-Hostwenn er USE_X_FORWARDED_HOSTaktiviert ist) keinem Wert in dieser Liste entspricht, wird die django.http.HttpRequest.get_host()Methode ausgelöst SuspiciousOperation.

... Diese Validierung gilt nur über get_host(); Wenn Ihr Code direkt von request.METAIhnen auf den Host-Header zugreift , wird dieser Sicherheitsschutz umgangen.


In Django 1.8request haben sich die Funktionsaufrufe für das Rendern von Vorlagen in Ihrer Vorlage geändert , sodass Sie sie nicht mehr verarbeiten müssenRequestContext direkt .

So rendern Sie eine Vorlage für eine Ansicht mithilfe der Verknüpfungsfunktion render():

from django.shortcuts import render

def my_view(request):
    ...
    return render(request, 'my_template.html', context)

So rendern Sie eine Vorlage für eine E-Mail. IMO ist der häufigste Fall, in dem Sie den Hostwert möchten:

from django.template.loader import render_to_string

def my_view(request):
    ...
    email_body = render_to_string(
        'my_template.txt', context, request=request)

Hier ist ein Beispiel für das Hinzufügen einer vollständigen URL zu einer E-Mail-Vorlage. request.scheme sollte erhalten httpoder httpsabhängig davon, was Sie verwenden:

Thanks for registering! Here's your activation link:
{{ request.scheme }}://{{ request.get_host }}{% url 'registration_activate' activation_key %}
S. Kirby
quelle
10

Ich verwende ein benutzerdefiniertes Vorlagen-Tag. Hinzufügen zu zB <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

Verwenden Sie es in einer Vorlage wie dieser:

{% load site %}
{% current_domain %}
Dennis Golomazov
quelle
Gibt es einen besonderen Nachteil bei diesem Ansatz? Abgesehen von dem Aufruf der Site db bei jeder Anfrage.
kicker86
@ kicker86 Ich kenne keine. get_currentist eine dokumentierte Methode: docs.djangoproject.com/de/dev/ref/contrib/sites/…
Dennis Golomazov
3
'http://%s'könnte im Falle einer httpsVerbindung ein Problem sein ; Schema ist in diesem Fall nicht dynamisch.
Beschädigte Bio
4

Ähnlich wie bei der Antwort von Benutzer panchicore habe ich dies auf einer sehr einfachen Website getan. Es enthält einige Variablen und stellt sie in der Vorlage zur Verfügung.

SITE_URLwürde einen Wert wie example.com
SITE_PROTOCOLhalten würde einen Wert wie halten http oder https
SITE_PROTOCOL_URLwürde einen Wert wie halten http://example.comoder https://example.com
SITE_PROTOCOL_RELATIVE_URLwürde einen Wert wie halten //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'

Dann auf die Vorlagen, nutzen sie als {{ SITE_URL }}, {{ SITE_PROTOCOL }}, {{ SITE_PROTOCOL_URL }}und{{ SITE_PROTOCOL_RELATIVE_URL }}

Julián Landerreche
quelle
2

In einer Django-Vorlage können Sie Folgendes tun:

<a href="{{ request.scheme }}://{{ request.META.HTTP_HOST }}{{ request.path }}?{{ request.GET.urlencode }}" >link</a>
DOS
quelle
1
Das hat bei mir funktioniert, danke. Ich musste die Anfrage in TEMPLATES, context_processors: aktivieren django.template.context_processors.request, auch [diese Anleitung half] ( simpleisbetterthancomplex.com/tips/2016/07/20/… )
ionescu77
Stimmen Sie zu, Vitor Freitas Blog ist eine großartige Quelle für Django-Entwickler! :)
Dos
2

Wenn Sie den Kontextprozessor "request" verwenden und das Django-Sites-Framework verwenden und die Site-Middleware installiert haben (dh Ihre Einstellungen umfassen diese):

INSTALLED_APPS = [
    ...
    "django.contrib.sites",
    ...
]

MIDDLEWARE = [
    ...
     "django.contrib.sites.middleware.CurrentSiteMiddleware",
    ...
]

TEMPLATES = [
    {
        ...
        "OPTIONS": {
            "context_processors": [
                ...
                "django.template.context_processors.request",
                ...
            ]
        }
    }
]

... dann haben Sie das requestObjekt in Vorlagen zur Verfügung und es enthält einen Verweis auf den aktuellen Sitefür die Anfrage als request.site. Sie können die Domain dann in einer Vorlage abrufen mit:

    {{request.site.domain}}
user85461
quelle
1

Was ist mit diesem Ansatz? Funktioniert bei mir. Es wird auch bei der Django-Registrierung verwendet .

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)

quelle
Wenn Sie es jedoch versuchen, localhosterhalten Sie ein httpsSchema (es wird als sicher angesehen), das nicht funktioniert, wenn Sie eine statische URL haben (nur http://127.0.0.1gültig, nicht gültig https://127.0.0.1). Es ist also nicht ideal, wenn es sich noch in der Entwicklung befindet.
ThePhi
0
from django.contrib.sites.models import Site
if Site._meta.installed:
    site = Site.objects.get_current()
else:
    site = RequestSite(request)
Muneeb Ahmad
quelle
-5

Sie können {{ protocol }}://{{ domain }}in Ihren Vorlagen verwenden, um Ihren Domain-Namen zu erhalten.

Erwan
quelle
Ich glaube nicht, dass @Erwan bemerkt, dass dies von einem nicht standardmäßigen Anforderungskontextprozessor abhängt.
Monokrom
Ich konnte das nicht zum Laufen bringen. Wo definieren Sie Protokoll und Domäne?
Jose Luis de la Rosa