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


Antworten:


67

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


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.


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.


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.


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

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

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


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

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

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


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>

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

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)

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)

-5

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


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.