Wie kann ich die vollständige / absolute URL (mit Domain) in Django erhalten?

379

Wie kann ich die vollständige / absolute URL (z. B. https://example.com/some/path) in Django ohne das Sites-Modul erhalten ? Das ist einfach albern ... Ich sollte meine Datenbank nicht abfragen müssen, um die URL zu knacken!

Ich möchte es mit verwenden reverse().

mpen
quelle
11
Nebenbei bemerkt: Das Sites-Modul trifft die Datenbank nur, wenn es zum ersten Mal den Site-Namen benötigt. Das Ergebnis wird in einer Modulvariablen (SITE_CACHE) zwischengespeichert, die bis zur Neukompilierung des Moduls oder des SiteManager.clear_cache () erhalten bleibt. Methode wird aufgerufen. Siehe: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
Colonel Sponsz

Antworten:

512

Verwenden Sie auf Anfrage die praktische Methode request.build_absolute_uri () , übergeben Sie ihr die relative URL und Sie erhalten eine vollständige.

Standardmäßig wird die absolute URL für request.get_full_path()zurückgegeben, Sie können jedoch eine relative URL als erstes Argument übergeben, um sie in eine absolute URL zu konvertieren.

Dmitry Shevchenko
quelle
3
Was ist mit der URL: localhost / home / # / test ? Ich kann nur localhost / home sehen . Wie kann ich das Teil nach scharf sehen ?
Sergzach
41
Alles, nachdem # nicht an den Server übergeben wurde, ist eine Nur-Browser-Funktion
Dmitry Shevchenko
70
In einer Vorlage (in der Sie keine Parameter {{ request.build_absolute_uri }}{{ object.get_absolute_url }}angeben können) können Sie dies einfach tun: - und heyho, vollständige URL.
Odinho - Velmont
17
Und was ist, wenn ich keinen Zugriff auf Anfragen habe? Wie in den Serialisierern von Django-REST-Framework?
Minder
15
Ich musste verwenden, {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}weil ich {{ request.build_absolute_uri }}einen abschließenden Schrägstrich hatte und {{ object.get_absolute_url }}mit einem Schrägstrich begann, der zu doppelten Schrägstrichen in der URL führte.
Xtranophilist
96

Wenn Sie es mit verwenden möchten, reverse()können Sie dies tun:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))

ébewè
quelle
3
Danke für die hilfreiche Antwort. Nichts ist besser als der Code selbst. (auch du url_nameview_name
meintest
3
@ Anupam reverse () ist definiert als:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
Matias Elgart
57

Sie können auch get_current_siteals Teil der Site-App ( from django.contrib.sites.models import get_current_site) verwenden. Es wird ein Anforderungsobjekt verwendet und standardmäßig das Site-Objekt verwendet, mit dem Sie SITE_IDin settings.py konfiguriert haben, wenn die Anforderung lautet None. Weitere Informationen zur Verwendung des Site-Frameworks finden Sie in der Dokumentation

z.B

from django.contrib.sites.shortcuts import get_current_site
request = None
full_url = ''.join(['http://', get_current_site(request).domain, obj.get_absolute_url()])

Es ist nicht so kompakt / ordentlich wie request.build_absolute_url(), aber es kann verwendet werden, wenn Anforderungsobjekte nicht verfügbar sind und Sie eine Standard-Site-URL haben.

Darb
quelle
4
Ich glaube, meine Frage lautete ausdrücklich "ohne das Sites-Modul". Trifft dies die DB?
Mpen
1
Das Sites-Modul wurde mithilfe von Caching auf Modulebene in das Zwischenspeichern von Site-Objekten geschrieben (dh Sie benötigen das Cache-Framework nicht), sodass die Datenbank nur beim ersten Abrufen einer Site durch einen Webprozess getroffen werden sollte. Wenn Sie nicht django.contrib.sitesin Ihrem haben INSTALLED_APPS, wird es die DB überhaupt nicht treffen und Informationen basierend auf dem Request-Objekt bereitstellen (siehe get_current_site )
Darb
1
Na dann kann man eine +1 haben, build_absolute_urisieht aber trotzdem nach der einfacheren und saubereren Lösung aus.
Mpen
1
Dies ist eine perfekte Antwort, wenn Sie versuchen, URLs in Signalen zu generieren, von denen E-Mails versendet werden sollen.
Chris
2
Funktioniert nicht, wenn Sie https verwenden. Ja, Sie könnten das s hinzufügen, aber entwickeln Sie mit https lokal? und wissen Sie immer, ob Sie https haben, aber nicht manchmal ...?
Tjati
55

Wenn Sie keinen Zugriff requestdarauf erhalten, können Sie diese get_current_site(request)in einigen Lösungen hier nicht wie empfohlen verwenden. Sie können get_absolute_urlstattdessen eine Kombination aus dem nativen Sites-Framework verwenden. Richten Sie mindestens eine Site im Administrator ein. Stellen Sie sicher, dass Ihr Modell über eine get_absolute_url () -Methode verfügt. Dann:

>>> from django.contrib.sites.models import Site
>>> domain = Site.objects.get_current().domain
>>> obj = MyModel.objects.get(id=3)
>>> path = obj.get_absolute_url()

>>> url = 'http://{domain}{path}'.format(domain=domain, path=path)
>>> print(url)
'http://example.com/mymodel/objects/3/'

https://docs.djangoproject.com/de/dev/ref/contrib/sites/#getting-the-current-domain-for-full-urls

Shacker
quelle
7
Dies ist sehr praktisch, wenn Sie keinen Zugriff auf das HttpRequest-Objekt haben. zB bei Aufgaben, Signalen etc.
Arsham
6
Bevor Sie dies verwenden, sollten Sie das Sites Framework docs.djangoproject.com/de/dev/ref/contrib/sites/…
madzohan
So ändern Sie example.com auch in etwas: Site.objects.all () [0] gibt 'example.com' zurück und hat die ID = 1, die in settings.py angegeben ist. Führen Sie einfach Site.objects.create aus (name = 'Produktion', domain = 'prodsite.com') und setzen Sie SITE_ID = 2 in settings.py. Jetzt gibt Site.objects.get_current (). Domain 'prodsite.com' zurück.
gek
Sie können festlegen , requestauf Noneoder Anruf get_current_site(None).
Bobort
20

Wenn Sie nicht auf die Datenbank zugreifen möchten, können Sie dies mit einer Einstellung tun. Verwenden Sie dann einen Kontextprozessor, um ihn jeder Vorlage hinzuzufügen:

# settings.py (Django < 1.9)
...
BASE_URL = 'http://example.com'
TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    'myapp.context_processors.extra_context',
)
# settings.py (Django >= 1.9)
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                # Additional
                'myapp.context_processors.extra_context',
            ],
        },
    },
]

# myapp/context_processors.py
from django.conf import settings

def extra_context(request):
    return {'base_url': settings.BASE_URL}

# my_template.html
<p>Base url is {{ base_url }}.</p>
seddonym
quelle
17

Tun Sie Ihrer Ansicht nach einfach Folgendes:

base_url =  "{0}://{1}{2}".format(request.scheme, request.get_host(), request.path)
levi
quelle
14

django-fullurl

Wenn Sie versuchen, dies in einer Django-Vorlage zu tun, habe ich ein winziges PyPI-Paket veröffentlicht django-fullurl, mit dem Sie Tags durch und wie folgt ersetzen urlund vorlegen können:staticfullurlfullstatic

{% load fullurl %}

Absolute URL is: {% fullurl "foo:bar" %}

Another absolute URL is: {% fullstatic "kitten.jpg" %}

Diese Abzeichen sollten hoffentlich automatisch auf dem neuesten Stand bleiben:

PyPI Travis CI

In einer Ansicht können Sie natürlich request.build_absolute_uristattdessen verwenden.

Flimm
quelle
Schade, dass dies mit 2.0 nicht funktioniert. Möglicherweise muss eine PR hochgeschoben werden.
Steven Church
@StevenChurch Es sollte funktionieren. Ich habe Django 2.0 noch nicht als unterstützt markiert, aber die vorhandene Version sollte funktionieren.
Flimm
Für meine Bedürfnisse habe ich dies umgangen, indem ich eine ENV von Heroku zum Failback übergeben habe. Mein Problem besteht darin, dass die URL an E-Mail-Vorlagen weitergeleitet wird. Ich kann mich nicht an das Problem erinnern, aber es hat aufgrund einer Django-Änderung nicht funktioniert.
Steven Church
@StevenChurch Ich denke, das Problem beim Erstellen von E-Mails ist, dass es kein requestObjekt gibt, von dem der Domainname abgerufen werden kann . In diesem Fall sollten Sie sitesstattdessen das Framework verwenden, das den Domänennamen aus der Datenbank abruft. Siehe django-absoluteuriim Abschnitt "Siehe auch" der README-Datei dieses PyPI-Pakets.
Flimm
8

So erstellen Sie einen vollständigen Link zu einer anderen Seite aus einer Vorlage:

{{ request.META.HTTP_HOST }}{% url 'views.my_view' my_arg %}

request.META.HTTP_HOST gibt den Hostnamen und url den relativen Namen an. Die Template-Engine verkettet sie dann zu einer vollständigen URL.

Doug Bradshaw
quelle
2
In der Antwort fehlen das Protokoll ( httpin diesem Zusammenhang) und ein ://Teil der URL, sodass keine vollständige URL bereitgestellt wird .
user272735
2
Auf dem Anforderungsobjekt befindet sich ein Host. Untersuchen Sie Meta nicht direkt: docs.djangoproject.com/de/1.8/ref/request-response/…
Kit Sunde
8

Noch ein anderer Weg. Sie können build_absolute_uri()in Ihrem verwenden view.pyund es an die Vorlage übergeben.

view.py

def index(request):
    baseurl = request.build_absolute_uri()
    return render_to_response('your-template.html', { 'baseurl': baseurl })

your-template.html

{{ baseurl }}
Sven Rojek
quelle
HttpRequest.build_absolute_uri(request)ist gleichbedeutend mit request.build_absolute_uri()nicht wahr?
Mpen
7

Untersuchen Sie Request.METAdas eingehende Wörterbuch. Ich denke, es hat den Servernamen und den Serverport.

Kugel
quelle
2
benutze request.META ['HTTP_HOST']
Antony
4
Auf dem Anforderungsobjekt befindet sich ein Host. Untersuchen Sie Meta nicht direkt: docs.djangoproject.com/de/1.8/ref/request-response/…
Kit Sunde
7

Versuchen Sie den folgenden Code:

{{ request.scheme }}://{{ request.META.HTTP_HOST }}
Kennzeichen
quelle
Das gibt nur die Domain ohne den Pfad und die Abfragezeichenfolge, nein?
Mpen
6

Das hat bei mir in meiner Vorlage funktioniert:

{{ request.scheme }}:{{ request.META.HTTP_HOST }}{% url  'equipos:marca_filter' %}

Ich brauchte die vollständige URL, um sie an eine js-Abruffunktion zu übergeben. Ich hoffe das hilft dir.

Jose Luis Quichimbo
quelle
5

Ich weiß, das ist eine alte Frage. Aber ich denke, die Leute stoßen immer noch oft darauf.

Es gibt einige Bibliotheken, die die Standard-Django-Funktionalität ergänzen. Ich habe ein paar ausprobiert. Ich mag die folgende Bibliothek, wenn absolute URLs umgekehrt referenziert werden:

https://github.com/fusionbox/django-absoluteuri

Eine andere, die mir gefällt, weil Sie einfach eine Domäne, ein Protokoll und einen Pfad zusammenstellen können, ist:

https://github.com/RRMoelker/django-full-url

Mit dieser Bibliothek können Sie einfach schreiben, was Sie in Ihre Vorlage einfügen möchten, z.

{{url_parts.domain}}
johniak20
quelle
4

Wenn Sie das Django REST-Framework verwenden, können Sie die Umkehrfunktion von verwenden rest_framework.reverse. Dies hat das gleiche Verhalten wie django.core.urlresolvers.reverse, außer dass ein Anforderungsparameter zum Erstellen einer vollständigen URL verwendet wird.

from rest_framework.reverse import reverse

# returns the full url
url = reverse('view_name', args=(obj.pk,), request=request)

# returns only the relative url
url = reverse('view_name', args=(obj.pk,))

Bearbeitet, um die Verfügbarkeit nur im REST-Framework zu erwähnen

JohnG
quelle
Ich erhalte eine Fehlermeldung mit request=request. Es scheint auch nicht so, als ob die Anfrage hier dokumentiert ist. Docs.djangoproject.com/de/1.9/ref/urlresolvers/#reverse
Ryan Amos
Ich habe vergessen zu erwähnen, dass dies nur verfügbar ist, wenn Sie das REST-Framework verwenden. Guter Fang, ich habe meine Antwort aktualisiert.
JohnG
Ja, danke - das funktioniert wie ein Zauber mit Django REST Framework
Apoorv Kansal
1

Ich habe es bekommen:

wsgiref.util.request_uri(request.META)

Holen Sie sich die vollständige URL mit Schema, Host, Portpfad und Abfrage.

Wunder
quelle
0

Als Einstellung steht auch ABSOLUTE_URL_OVERRIDES zur Verfügung

https://docs.djangoproject.com/de/2.1/ref/settings/#absolute-url-overrides

Dies überschreibt jedoch get_absolute_url (), was möglicherweise nicht wünschenswert ist.

Anstatt das Site-Framework nur dafür zu installieren oder einige der anderen hier genannten Dinge zu tun, die auf dem Anforderungsobjekt beruhen, ist es meiner Meinung nach die bessere Lösung, dies in models.py zu platzieren

Definieren Sie BASE_URL in settings.py, importieren Sie es dann in models.py und erstellen Sie eine abstrakte Klasse (oder fügen Sie sie einer bereits verwendeten hinzu), die get_truly_absolute_url () definiert. Es könnte so einfach sein wie:

def get_truly_absolute_url(self):
    return BASE_URL + self.get_absolute_url()

Unterklasse es und jetzt können Sie es überall verwenden.

aris
quelle
0

Wie in anderen Antworten erwähnt, request.build_absolute_uri()ist es perfekt, wenn Sie Zugriff auf requestund habensites Framework ist großartig, solange verschiedene URLs auf verschiedene Datenbanken verweisen.

Mein Anwendungsfall war jedoch etwas anders. Mein Staging-Server und der Produktionsserver greifen auf dieselbe Datenbank zu, aber get_current_sitebeide haben den ersten sitein der Datenbank zurückgegeben. Um dies zu beheben, müssen Sie eine Art Umgebungsvariable verwenden. Sie können entweder 1) eine Umgebungsvariable (so etwas wie os.environ.get('SITE_URL', 'localhost:8000')) oder 2) verschiedene SITE_IDs für verschiedene Server UND verschiedene settings.py verwenden .

Hoffentlich findet das jemand nützlich!

Bartleby
quelle
0

Ich bin auf diesen Thread gestoßen, weil ich einen absoluten URI für eine Erfolgsseite erstellen wollte. request.build_absolute_uri()gab mir eine URI für meine aktuelle Ansicht, aber um die URI für meine Erfolgsansicht zu erhalten, habe ich Folgendes verwendet ...

request.build_absolute_uri (umgekehrt ('success_view_name'))

Soundtemple
quelle
-2

request.get_host() wird Ihnen die Domain geben.

Roge
quelle
1
Die Frage besagt, vollständige URL
acidjunk
-5

Sie können auch verwenden:

import socket
socket.gethostname()

Das funktioniert gut für mich,

Ich bin mir nicht ganz sicher, wie es funktioniert. Ich glaube, dies ist etwas niedriger und gibt Ihren Server-Hostnamen zurück, der sich möglicherweise von dem Hostnamen unterscheidet, den Ihr Benutzer verwendet, um auf Ihre Seite zu gelangen.

Eduardo
quelle
Ja ... Sie haben auf das Problem hingewiesen. Der Hostname muss nicht unbedingt mit dem Domainnamen identisch sein.
Mpen
Dies löst ein ganz anderes Problem. Stellen Sie sich einen gemeinsam genutzten Hosting-Server mit mehreren Websites vor. Unter Verwendung des obigen Codes weisen alle Websites, die URLs generieren, alle diese URLs auf den Host-Computer, bei dem es sich wahrscheinlich NICHT um eine der ausgeführten Websites handelt.
TBB
-6

Sie können "request.get_full_path ()" ausprobieren.

Max Ferreira
quelle
3
Dies beinhaltet nicht die Domain.
TAH