Как я могу получить полный / абсолютный URL (с доменом) в Django?

380

Как я могу получить полный / абсолютный URL (например https://example.com/some/path) в Django без модуля Sites ? Это просто глупо ... Мне не нужно запрашивать мою БД, чтобы поймать URL!

Я хочу использовать это с reverse().

mpen
источник
11
Напомним, что модуль sites обращается к БД только в первый раз, когда ему нужно имя сайта, результат кэшируется в переменной модуля (SITE_CACHE), которая будет сохраняться до повторной компиляции модуля или SiteManager.clear_cache (). метод называется. См .: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
полковник Спонс

Ответы:

513

Используйте удобный метод request.build_absolute_uri () по запросу, передайте ему относительный URL, и он даст вам полный.

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

Дмитрий Шевченко
источник
3
Как насчет URL: localhost / home / # / test ? Я могу видеть только localhost / home . Как я могу увидеть часть после резкого ?
sergzach
41
все, что после # не передается на сервер, это функция только для браузера
Дмитрий Шевченко
70
В шаблоне (где вы не можете {{ request.build_absolute_uri }}{{ object.get_absolute_url }}указать параметры) вы можете просто сделать это: - и heyho, полный URL.
Одино - Велмонт
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.
Экстранофилист
97

Если вы хотите использовать его вместе с reverse()вами, вы можете сделать это:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))

EBEWE
источник
3
Спасибо за полезный ответ. Нет ничего лучше, чем сам код. (также вы, вероятно, имели в виду, url_nameа не view_name)
Anupam
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, но не иногда ...?
Тяти
56

Если вы не можете получить доступ к нему, requestвы не можете использовать его get_current_site(request)в соответствии с рекомендациями, приведенными здесь. Вы можете использовать комбинацию нативной платформы Sites и 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

shacker
источник
7
Это действительно удобно, когда у вас нет доступа к объекту HttpRequest. например, в задачах, сигналах и т. д.
Arsham
6
перед использованием этого вы должны включить каркас сайтов docs.djangoproject.com/en/dev/ref/contrib/sites/…
madzohan
Чтобы изменить example.com на что-то также: Site.objects.all () [0] возвращает «example.com» и имеет id = 1, который указан в settings.py. Просто сделайте Site.objects.create (name = 'production', domain = 'prodsite.com') и установите SITE_ID = 2 в settings.py. Теперь Site.objects.get_current (). Domain возвращает «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>
seddonym
источник
17

По вашему мнению, просто сделайте это:

base_url =  "{0}://{1}{2}".format(request.scheme, request.get_host(), request.path)
Levi
источник
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-адреса для передачи по шаблонам электронной почты. Я не могу вспомнить проблему, но она не сработала из-за изменения в Django.
Стивен Черч
@ 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-адрес .
user272735
2
У объекта запроса есть хост. Не проверяйте мета непосредственно: docs.djangoproject.com/en/1.8/ref/request-response/…
Кит
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 })

ваш-template.html

{{ baseurl }}
Свен Роек
источник
HttpRequest.build_absolute_uri(request)эквивалентно request.build_absolute_uri()не так ли?
mpen
7

Изучите Request.METAвходящий словарь. Я думаю, что он имеет имя сервера и порт сервера.

Кугель
источник
2
используйте request.META ['HTTP_HOST']
Энтони
4
У объекта запроса есть хост. Не проверяйте мета непосредственно: docs.djangoproject.com/en/1.8/ref/request-response/…
Кит
7

Попробуйте следующий код:

{{ request.scheme }}://{{ request.META.HTTP_HOST }}
отметка
источник
Это просто даст домен без пути и строки запроса, не так ли?
mpen
6

Это сработало для меня в моем шаблоне:

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

Мне нужен был полный URL, чтобы передать его в функцию js fetch. Я надеюсь, что это поможет вам.

Хосе Луис Кичимбо
источник
5

Я знаю, что это старый вопрос. Но я думаю, что люди все еще сталкиваются с этим.

Есть несколько библиотек, которые дополняют стандартную функциональность Django. Я попробовал несколько. Мне нравится следующая библиотека при обратной ссылке на абсолютные URL:

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

Еще один, который мне нравится, потому что вы можете легко собрать домен, протокол и путь:

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

Эта библиотека позволяет вам просто написать то, что вы хотите в своем шаблоне, например:

{{url_parts.domain}}
johniak20
источник
4

Если вы используете django REST framework, вы можете использовать функцию reverse из 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

JohnG
источник
Я получаю ошибку, используя request=request. Также не похоже, что запрос задокументирован здесь. Docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Райан Амос
Я забыл упомянуть, что это доступно только если вы используете REST Framework. Хороший улов, я обновил свой ответ.
JohnG
Да, спасибо - это работает как шарм с Django REST framework
Apoorv Kansal
1

Я понял:

wsgiref.util.request_uri(request.META)

Получите полный URI со схемой, хостом, путем к порту и запросом.

задаваться вопросом
источник
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()

Подкласс это и теперь вы можете использовать его везде.

ARIS
источник
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 (обратный ( 'success_view_name'))

Soundtemple
источник
-2

request.get_host() даст вам домен.

Roge
источник
1
Вопрос гласит, полный URL
acidjunk
-5

Вы также можете использовать:

import socket
socket.gethostname()

Это работает нормально для меня,

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

Эдуардо
источник
Да .. Вы указали на проблему. Имя хоста не обязательно совпадает с именем домена.
mpen
Это решает совсем другую проблему. Рассмотрим сервер общего хостинга с несколькими веб-сайтами - используя приведенный выше код, все сайты, генерирующие URL-адреса, будут иметь все такие URL-адреса, указывающие на хост-компьютер, который, скорее всего, НЕ является ни одним из работающих веб-сайтов.
TBM
-6

Вы можете попробовать "request.get_full_path ()"

Макс Феррейра
источник
3
Это не включает домен.
TAH