Як я можу отримати повну / абсолютну URL-адресу (з доменом) у Django?


379

Як я можу отримати повну / абсолютну URL-адресу (наприклад https://example.com/some/path) у Django без модуля Sites ? Це просто нерозумно ... Мені не потрібно запитувати мій БД, щоб зафіксувати URL!

Я хочу його використовувати reverse().


11
Як і в сторону: Модуль сайтів потрапляє в БД тільки в перший раз, коли йому потрібна назва сайту, результат кешується в змінній модулі (SITE_CACHE), яка буде триматися навколо до повторної компіляції модуля або SiteManager.clear_cache () метод називається. Дивіться: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
полковник Спонш

Відповіді:


512

Скористайтеся зручним методом request.build_absolute_uri () за запитом, передайте йому відносну URL-адресу, і вона дасть вам повний.

За замовчуванням абсолютна URL-адреса request.get_full_path()повертається, але ви можете передати її відносною URL-адресою як перший аргумент для перетворення її в абсолютну URL-адресу.


3
Що щодо URL-адреси: localhost / home / # / test ? Я бачу лише localhost / home . Як я бачу деталь після різкої ?
sergzach

41
все після # не передається серверу, це лише функція браузера
Дмитро Шевченко,

69
У шаблоні (де ви не можете вказати параметри) ви можете просто зробити це: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- і heyho, повна URL-адреса.
odinho - Велмонт

17
А що робити, якщо я не маю доступу до запиту? Як у серіалізаторах Django-REST-Framework?
мислитель

15
Мені довелося скористатися, {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}тому що {{ request.build_absolute_uri }}був косою косою рисою і {{ object.get_absolute_url }}почався з косою косою рисою, що призвело до подвійних косих косих в URL-адресі.
xtranophilist

96

Якщо ви хочете скористатися ним, reverse()ви можете зробити це:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))


3
Дякуємо за корисну відповідь. Нічого кращого, ніж сам код. (також ви, мабуть, мали на увазі url_nameзамість view_name)
Анупам,

3
@Anupam reverse () визначається як:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart

57

Ви також можете використовувати get_current_siteяк частину програми для сайтів ( from django.contrib.sites.models import get_current_site). Він займає об’єкт запиту і за замовчуванням відповідає об’єкту сайту, з яким ви налаштувались SITE_IDу settings.py, якщо запит є None. Детальніше читайте в документації щодо використання фреймворку сайтів

напр

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

Він не настільки компактний / охайний request.build_absolute_url(), але він доступний, коли об’єкти запиту недоступні, і у вас є URL-адреса сайту за замовчуванням.


4
Я вважаю, що моє питання спеціально говорило "без модуля Сайтів". Це потрапило в БД?
mpen

1
Модуль Sites був записаний для кешування об'єктів Site, використовуючи кешування рівня модуля (тобто вам не потрібна рамка кешу), тому БД повинен потрапляти лише під час першого завантаження сайту через веб-процес. Якщо у вас немає django.contrib.sitesв вашій INSTALLED_APPS, він не потрапив в БД на всіх, і надати інформацію , засновану на об'єкті запиту (див get_current_site )
Дарб

1
Добре, тоді ви можете мати +1, але build_absolute_uriвсе одно виглядає як простіше і чистіше рішення.
mpen

1
Це ідеальна відповідь, якщо ви намагаєтеся генерувати URL-адреси в сигналах, з яких відправляти електронні листи.
Кріс

2
Не працює, якщо ви використовуєте https. Так, ви можете додати s, але чи розвиваєтесь ви з https локально? і чи завжди ви знаєте, якщо у вас є https, але не іноді ...?
tjati

55

Якщо ви не можете отримати доступ до requestцього, ви не можете використовувати, get_current_site(request)як рекомендовано в деяких рішеннях тут. Ви можете використовувати комбінацію нативного фрейма Сайтів і get_absolute_urlзамість цього. Налаштуйте принаймні один Сайт у адміністратора, переконайтеся, що у вашій моделі є метод get_absolute_url () , а потім:

>>> 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
Це дуже зручно, коли у вас немає доступу до об’єкта HttpRequest. наприклад, у завданнях, сигналах тощо
Аршам

6
перед тим, як скористатись цим, слід включити веб-сайти Framework docs.djangoproject.com/en/dev/ref/contrib/sites/…
madzohan

Щоб змінити example.com на щось також: Site.objects.all () [0] повертає 'example.com' і має id = 1, який вказано в settings.py. Просто зробіть Site.objects.create (ім'я = 'виробництво', домен = 'prodsite.com') і встановіть SITE_ID = 2 у settings.py. Тепер домен Site.objects.get_current (). Повертає "prodsite.com".
gek

Ви можете встановити requestна Noneабо зателефонувавши по телефону get_current_site(None).
Бобборт

20

Якщо ви не хочете потрапляти в базу даних, ви можете зробити це з налаштуванням. Потім використовуйте контекстний процесор, щоб додати його до кожного шаблону:

# 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

На ваш погляд, просто зробіть це:

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

14

django-fullurl

Якщо ви намагаєтеся це зробити в шаблоні Django, я випустив крихітний пакет PyPI, django-fullurlщоб дозволити вам замінювати urlта staticтеги шаблонів на fullurlі fullstatic, як це:

{% load fullurl %}

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

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

Сподіваємось, ці значки повинні постійно оновлюватися автоматично:

PyPI Тревіс CI

Зрозуміло, ви можете, звичайно, використовувати request.build_absolute_uriзамість цього.


Соромно, що це не працює з 2.0. Можливо, потрібно підштовхнути PR.
Церква Стівена

@StevenChurch Це повинно працювати. Я ще не позначив Django 2.0 як підтримуваний, але існуюча версія повинна працювати.
Flimm

Для моїх потреб я обійшов це, передавши ENV від Heroku для відмови. Моя проблема полягає в отриманні URL-адреси, яку потрібно передати шаблонам електронної пошти. Я не можу пригадати проблему, але вона не спрацювала через зміну Джанго.
Церква Стівена

@StevenChurch Я думаю, що проблема при створенні електронних листів полягає в тому, що немає requestоб’єкта, з якого можна отримати доменне ім'я. У цьому випадку вам слід скористатись sitesфреймворком, який отримує доменне ім'я з бази даних. Дивіться django-absoluteuri, згаданий у розділі "див. Також" README цього пакету PyPI.
Flimm

8

Щоб створити повне посилання на іншу сторінку з шаблону, ви можете скористатися цим:

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

request.META.HTTP_HOST вказує ім'я хоста, а url - відносне ім'я. Потім механізм шаблонів об'єднує їх у повний URL.


2
У відповіді відсутній протокол ( httpу цьому контексті) та ://частина URL-адреси, тому він не надаватиме повну URL-адресу .
користувач272735

2
Об'єкт запиту має хост. Не вивчайте
Kit Sunde

8

Ще інший спосіб. Ви можете використовувати build_absolute_uri()у своєму view.pyі передавати його до шаблону.

view.py

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

your-template.html

{{ baseurl }}

HttpRequest.build_absolute_uri(request)еквівалентно request.build_absolute_uri()чи не так?
mpen


7

Спробуйте наступний код:

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

Це просто дасть домен без шляху та рядка запиту, ні?
1616

6

Це працювало для мене в моєму шаблоні:

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

Мені потрібна була повна URL-адреса, щоб передати її до функції отримання js. Я сподіваюся, що це допоможе тобі.


5

Я знаю, це старе питання. Але я думаю, що люди все ще багато стикаються з цим.

Є кілька бібліотек, які доповнюють функціональність Django за замовчуванням. Я спробував кілька. Мені подобається наступна бібліотека при зворотному посиланні на абсолютні URL-адреси:

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

Ще один мені подобається, тому що ви можете легко скласти домен, протокол і шлях:

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

Ця бібліотека дозволяє просто записати те, що ви хочете у свій шаблон, наприклад:

{{url_parts.domain}}

4

Якщо ви використовуєте рамку django REST, ви можете використовувати функцію зворотного зв’язку від rest_framework.reverse. Це поведінка така сама, як django.core.urlresolvers.reverse, за винятком того, що він використовує параметр запиту для створення повної 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,))

Редаговано, щоб згадати про доступність лише в рамках REST


Я отримую помилку за допомогою request=request. Також не здається, що запит задокументований тут docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Райан Амос

Я забув згадати, що це доступно, лише якщо ви використовуєте рамку REST. Хороший улов, я оновив свою відповідь.
JohnG

Так, дякую - це працює як шарм із рамкою django REST
Апоорв Канзал

1

Зрозумів:

wsgiref.util.request_uri(request.META)

Отримайте повний урі за допомогою схеми, хоста, шляху до порту та запиту.


0

Також в якості налаштування доступні ABSOLUTE_URL_OVERRIDES

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

Але це переосмислює get_absolute_url (), що може бути не бажаним.

Замість того, щоб встановлювати рамки сайтів саме для цього або робити якісь інші згадані тут речі, які покладаються на об’єкт запиту, я думаю, що краще рішення - розмістити це в models.py

Визначте BASE_URL у settings.py, а потім імпортуйте їх у models.py та зробіть абстрактний клас (або додайте його до того, який ви вже використовуєте), який визначає get_truly_absolute_url (). Це може бути так само просто, як:

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

Підклас це, і тепер ви можете використовувати його всюди.


0

Як було сказано в інших відповідях, request.build_absolute_uri()ідеально підходить, якщо у вас є доступ до requestтаsites фреймворк чудовий, якщо різні URL-адреси вказують на різні бази даних.

Однак мій випадок використання був дещо іншим. Мій сервер та постановочний сервер отримують доступ до однієї бази даних, але get_current_siteобидва повернули першу siteв базі даних. Щоб вирішити це, вам потрібно використовувати якусь змінну середовища. Ви можете використовувати 1) змінну середовища (щось на зразок os.environ.get('SITE_URL', 'localhost:8000')) або 2) різні SITE_IDs для різних серверів І різних settings.py .

Сподіваємось, хтось знайде це корисним!


0

Я натрапив на цю тему, тому що шукав створити абсолютний URI для сторінки успіху. request.build_absolute_uri()дав мені URI для мого поточного перегляду, але для отримання URI для мого перегляду успіху я використав наступне ....

request.build_absolute_uri (зворотний ('ім'я успіху_відомості'))



-5

Ви також можете використовувати:

import socket
socket.gethostname()

Це добре для мене,

Я не зовсім впевнений, як це працює. Я вважаю, що це трохи нижчий рівень, і він поверне ім’я хоста вашого сервера, яке може відрізнятися від імені хоста, використовуваного вашим користувачем для переходу на вашу сторінку.


Так .. Ви вказали на проблему. Ім'я хоста не обов'язково те саме, що ім'я домену.
mpen

Це вирішує зовсім іншу проблему. Розглянемо спільний хостинг-сервер з декількома веб-сайтами - використовуючи код вище, усі сайти, що генерують URL-адреси, матимуть усі такі URL-адреси, що вказують на хост-апарат, що, ймовірно, НЕ будь-який із запущених веб-сайтів.
tbm

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.