Jak mogę uzyskać pełny / bezwzględny adres URL (z domeną) w Django?


379

Jak mogę uzyskać pełny / bezwzględny adres URL (np. https://example.com/some/path) W Django bez modułu Witryny? ? To po prostu głupie ... Nie powinienem wysyłać zapytań do mojej bazy danych, aby złapać adres URL!

Chcę go używać z reverse().


11
Tak na marginesie: moduł witryn trafia do bazy danych tylko wtedy, gdy potrzebuje nazwy witryny, wynik jest buforowany w zmiennej modułu (SITE_CACHE), która będzie się utrzymywać do momentu ponownej kompilacji modułu lub SiteManager.clear_cache () wywoływana jest metoda Zobacz: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
Pułkownik Sponsz

Odpowiedzi:


512

Użyj poręcznej metody request.build_absolute_uri () na żądanie, przekaż jej względny adres URL, a otrzymasz pełny.

Domyślnie request.get_full_path()zwracany jest bezwzględny adres URL dla , ale możesz przekazać mu względny adres URL jako pierwszy argument do przekonwertowania go na bezwzględny adres URL.


3
Co z adresem URL: localhost / home / # / test ? Widzę tylko localhost / home . Jak mogę zobaczyć część po ostrym ?
sergzach,

41
wszystko po # nie jest przekazywane do serwera, jest to funkcja tylko do przeglądarki
Dmitry Shevchenko

69
W szablonie (w którym nie możesz podać parametrów) możesz po prostu to zrobić: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- i hejho, pełny adres URL.
odinho

17
A jeśli nie mam dostępu do żądania? Jak w Serializatorach Django-REST-Framework?
minder

15
Musiałem użyć, {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}ponieważ {{ request.build_absolute_uri }}miałem ukośnik i {{ object.get_absolute_url }}zacząłem od ukośnika powodującego podwójne ukośniki w adresie URL.
xtranofilista

96

Jeśli chcesz go używać, reverse()możesz to zrobić:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))


3
Dziękuję za pomocną odpowiedź. Nic lepszego niż sam kod. (też prawdopodobnie miałeś na myśli url_namezamiast view_name)
Anupam

3
@Anupam reverse () jest zdefiniowany jako:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart

57

Możesz także użyć get_current_sitejako części aplikacji witryn ( from django.contrib.sites.models import get_current_site). Pobiera obiekt żądania i domyślnie przyjmuje obiekt strony, który skonfigurowałeś SITE_IDw pliku settings.py, jeśli jest to żądanie None. Przeczytaj więcej w dokumentacji dla korzystania ze struktury witryn

na przykład

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

Nie jest tak kompaktowy / schludny jak request.build_absolute_url(), ale można go używać, gdy obiekty żądań są niedostępne i masz domyślny adres URL witryny.


4
Uważam, że moje pytanie brzmiało „bez modułu Witryny”. Czy to uderza DB?
mpen

1
Moduł Witryny został napisany w celu buforowania obiektów Witryny przy użyciu buforowania na poziomie modułu (tzn. Nie potrzebujesz struktury pamięci podręcznej), więc DB powinien zostać trafiony tylko przy pierwszym pobraniu Witryny przez proces sieciowy. Jeśli go nie masz, django.contrib.sitesw INSTALLED_APPSogóle nie trafi do bazy danych i nie dostarczy informacji na podstawie obiektu żądania (patrz get_current_site )
Darb

1
Cóż, możesz mieć +1, ale build_absolute_urinadal wygląda na łatwiejsze i czystsze rozwiązanie.
mpen

1
To idealna odpowiedź, jeśli próbujesz generować adresy URL w sygnałach, z których wysyłane będą wiadomości e-mail.
Chris

2
Nie działa, jeśli używasz https. Tak, możesz dodać s, ale czy rozwijasz się lokalnie z https? i czy zawsze wiesz, czy masz https, ale nie czasami ...?
tjati

55

Jeśli nie możesz uzyskać dostępu request, nie możesz użyć tego, get_current_site(request)co jest zalecane w niektórych rozwiązaniach tutaj. Zamiast tego możesz użyć kombinacji natywnej struktury Witryn get_absolute_url. Skonfiguruj co najmniej jedną witrynę w adminie , upewnij się, że Twój model ma metodę get_absolute_url () , a następnie:

>>> 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/en/dev/ref/contrib/sites/#getting-the-current-domain-for-full-urls


7
Jest to bardzo przydatne, gdy nie masz dostępu do obiektu HttpRequest. np. w zadaniach, sygnałach itp.
Arsham,

6
przed użyciem należy włączyć framework witryn docs.djangoproject.com/en/dev/ref/contrib/sites/…
madzohan

Aby zmienić example.com na coś również: Site.objects.all () [0] zwraca „example.com” i ma id = 1, który określony jest w settings.py. Po prostu zrób Site.objects.create (name = 'production', domain = 'prodsite.com') i ustaw SITE_ID = 2 w settings.py. Teraz Site.objects.get_current (). Domena zwraca „prodsite.com”.
gek

Można ustawić requestdo Nonelub zadzwoń get_current_site(None).
Bobort

20

Jeśli nie chcesz trafić do bazy danych, możesz to zrobić za pomocą ustawienia. Następnie użyj procesora kontekstu, aby dodać go do każdego szablonu:

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

17

Twoim zdaniem po prostu zrób to:

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

14

django-fullurl

Jeśli próbujesz to zrobić w szablonie Django, wypuściłem niewielki pakiet PyPI, django-fullurlktóry pozwala ci zamieniać urli statictagi szablonów na fullurli fullstatic, tak:

{% load fullurl %}

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

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

Miejmy nadzieję, że te odznaki powinny być automatycznie aktualizowane:

PyPI Travis CI

W widoku możesz oczywiście użyć request.build_absolute_urizamiast tego.


Szkoda, że ​​to nie działa z 2.0. Może trzeba zwiększyć PR.
Steven Church,

@StevenChurch To powinno działać. Nie zaznaczyłem jeszcze Django 2.0 jako obsługiwanego, ale istniejąca wersja powinna działać.
Flimm,

Na moje potrzeby obejrzałem ten problem, przekazując ENV od Heroku na potrzeby powrotu po awarii. Moim problemem jest przesłanie adresu URL do szablonów wiadomości e-mail. Nie pamiętam problemu, ale nie działał z powodu zmiany Django.
Steven Church,

@StevenChurch Myślę, że problem podczas tworzenia wiadomości e-mail polega na tym, że nie ma requestobiektu, z którego można by uzyskać nazwę domeny. W takim przypadku powinieneś użyć sitesframeworka, który pobiera nazwę domeny z bazy danych. Patrz django-absoluteuriwspomniany w sekcji „patrz także” w pliku README tego pakietu PyPI.
Flimm,

8

Aby utworzyć kompletny link do innej strony z szablonu, możesz użyć tego:

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

request.META.HTTP_HOST podaje nazwę hosta, a adres URL podaje względną nazwę. Następnie silnik szablonów łączy je w pełny adres URL.


2
W odpowiedzi brakuje protokołu ( httpw tym kontekście) i ://części adresu URL, więc nie poda pełnego adresu URL .
user272735,

2
Obiekt żądania ma hosta. Nie badaj meta bezpośrednio: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde

8

Jeszcze inny sposób. Możesz użyć build_absolute_uri()w swoim view.pyi przekazać go do szablonu.

view.py

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

twój-szablon.html

{{ baseurl }}

HttpRequest.build_absolute_uri(request)jest równoważne, request.build_absolute_uri()prawda?
mpen


7

Wypróbuj następujący kod:

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

To da domenę bez ścieżki i ciągu zapytania, nie?
mpen

6

To zadziałało w moim szablonie:

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

Potrzebowałem pełnego adresu URL, aby przekazać go do funkcji pobierania js. Mam nadzieję, że ci to pomoże.


5

Wiem, że to stare pytanie. Ale myślę, że ludzie wciąż na to wpadają.

Istnieje kilka bibliotek, które uzupełniają domyślną funkcjonalność Django. Próbowałem kilka. Podoba mi się następująca biblioteka podczas odwrotnego odwoływania się do bezwzględnych adresów URL:

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

Innym, który podoba mi się, ponieważ możesz łatwo połączyć domenę, protokół i ścieżkę, jest:

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

Ta biblioteka pozwala po prostu napisać, co chcesz w szablonie, np .:

{{url_parts.domain}}

4

Jeśli używasz frameworka REST django, możesz użyć funkcji odwrotnej od rest_framework.reverse. Zachowuje się tak samo jak django.core.urlresolvers.reverse, z tym wyjątkiem, że używa parametru żądania do zbudowania pełnego adresu URL.

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

Edytowano, aby wspomnieć o dostępności tylko w ramach REST


Podczas używania pojawia się błąd request=request. Wydaje się również, że prośba nie jest udokumentowana tutaj docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Ryan Amos

Zapomniałem wspomnieć, że jest to dostępne tylko wtedy, gdy używasz frameworka REST. Dobry połów, zaktualizowałem swoją odpowiedź.
JohnG

Tak, dziękuję - to działa jak urok dzięki frameworkowi REST django
Apoorv Kansal

1

Mam to:

wsgiref.util.request_uri(request.META)

Uzyskaj pełny identyfikator URI ze schematem, hostem, ścieżką portu i zapytaniem.


0

Dostępne jest również ustawienie ABSOLUTE_URL_OVERRIDES

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

Ale to zastępuje get_absolute_url (), co może nie być pożądane.

Zamiast instalowania frameworku witryn tylko w tym celu lub wykonywania innych wymienionych tutaj czynności, które zależą od obiektu żądania, myślę, że lepszym rozwiązaniem jest umieszczenie tego w pliku models.py

Zdefiniuj BASE_URL w settings.py, a następnie zaimportuj go do models.py i utwórz klasę abstrakcyjną (lub dodaj ją do już używanej), która definiuje get_truly_absolute_url (). Może to być tak proste, jak:

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

Podklasuj go, a teraz możesz go używać wszędzie.


0

Jak wspomniano w innych odpowiedziach, request.build_absolute_uri()jest idealny, jeśli masz dostęp do requestisites struktura jest świetna, o ile różne adresy URL wskazują różne bazy danych.

Jednak mój przypadek użycia był nieco inny. Mój serwer pomostowy i serwer produkcyjny uzyskują dostęp do tej samej bazy danych, ale get_current_siteobie zwróciły pierwszą sitew bazie danych. Aby rozwiązać ten problem, musisz użyć jakiejś zmiennej środowiskowej. Możesz użyć 1) zmiennej środowiskowej (coś podobnego os.environ.get('SITE_URL', 'localhost:8000')) lub 2) różnych SITE_IDs dla różnych serwerów ORAZ różnych ustawień .py .

Mam nadzieję, że ktoś uzna to za przydatne!


0

Natknąłem się na ten wątek, ponieważ chciałem zbudować bezwzględny identyfikator URI strony sukcesu. request.build_absolute_uri()dał mi identyfikator URI dla mojego obecnego widoku, ale aby uzyskać identyfikator URI dla mojego widoku sukcesu, użyłem następującego ...

request.build_absolute_uri (rewers („nazwa_widoku_uduktu”))



-5

Możesz także użyć:

import socket
socket.gethostname()

To działa dobrze dla mnie,

Nie jestem do końca pewien, jak to działa. Uważam, że jest to nieco niższy poziom i zwróci nazwę hosta serwera, która może być inna niż nazwa hosta używana przez użytkownika w celu przejścia do strony.


Tak, wskazałeś problem. Nazwa hosta niekoniecznie jest taka sama jak nazwa domeny.
mpen 19.04.16

To rozwiązuje zupełnie inny problem. Rozważmy wspólny serwer hostingowy z wieloma stronami internetowymi - używając powyższego kodu, wszystkie strony generujące adresy URL będą miały wszystkie takie adresy URL wskazujące na maszynę hosta, co prawdopodobnie NIE jest żadną z działających stron.
tbm

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.