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


380

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

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


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


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


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>

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-адреса для передачи по шаблонам электронной почты. Я не могу вспомнить проблему, но она не сработала из-за изменения в 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.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}}

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


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

Я забыл упомянуть, что это доступно только если вы используете REST Framework. Хороший улов, я обновил свой ответ.
JohnG

Да, спасибо - это работает как шарм с Django REST framework
Apoorv Kansal


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



-5

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

import socket
socket.gethostname()

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

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


Да .. Вы указали на проблему. Имя хоста не обязательно совпадает с именем домена.
mpen

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.