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

315

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

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

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

19 ответов

472
Лучший ответ

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

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

  • 0
    +1 Эта функция использует те же данные, что и в моем ответе. И, безусловно, более удобный вариант.
  • 3
    А как насчет URL: localhost / home / # / test ? Я могу видеть только localhost / home . Как я могу увидеть часть после резкого ?
Показать ещё 10 комментариев
69

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

  • 3
    Спасибо за полезный ответ. Нет ничего лучше, чем сам код. (также вы, вероятно, имели в виду url_name вместо view_name )
  • 2
    @Anupam reverse () определяется как: def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
47

Вы также можете использовать 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
    Я считаю, что мой вопрос специально сказал "без модуля сайтов". Это поражает БД?
  • 1
    Модуль Sites был написан для кэширования объектов Site с использованием кэширования на уровне модуля (т. Е. Вам не нужна структура кэширования), поэтому БД должна попадать только при первом получении сайта веб-процессом. Если в INSTALLED_APPS вас нет django.contrib.sites , он вообще не попадет в БД и не предоставит информацию на основе объекта Request (см. Get_current_site )
Показать ещё 8 комментариев
40

Если вы не можете получить доступ к request, вы не можете использовать get_current_site(request), как рекомендуется в некоторых решениях здесь. Вместо этого вы можете использовать комбинацию структуры родных сайтов и get_absolute_url. Настройте хотя бы один Site в админке, убедитесь, что ваша модель имеет 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
    перед использованием этого вы должны включить каркас сайтов docs.djangoproject.com/en/dev/ref/contrib/sites/…
17

Если вы не хотите попасть в базу данных, вы можете сделать это с настройкой. Затем используйте контекстный процессор, чтобы добавить его в каждый шаблон:

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

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" %}

Эти значки должны, надеюсь, оставаться в курсе последних событий:

Изображение 916 Изображение 917Изображение 918[IMG_OUR_ID=919.svg?%20branch%20=%20master] Изображение 920

В представлении вы можете, конечно, использовать request.build_absolute_uri.

  • 0
    Позор это не работает с 2.0. Возможно, нужно подтолкнуть PR.
  • 0
    @ StevenChurch Это должно работать. Я не пометил Django 2.0 как поддерживаемый, но существующая версия должна работать.
Показать ещё 3 комментария
9

Чтобы создать полную ссылку на другую страницу из шаблона, вы можете использовать это:

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

request.META.HTTP_HOST указывает имя хоста, а url указывает относительное имя. Затем механизм шаблонов объединяет их в полный URL-адрес.

  • 2
    В ответе отсутствует протокол ( http в этом контексте) и :// часть URL, поэтому он не предоставит полный URL .
  • 2
    У объекта запроса есть хост. Не проверяйте мета напрямую: docs.djangoproject.com/en/1.8/ref/request-response/…
8

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

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

На ваш взгляд, просто сделайте следующее:

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

Еще один способ. Вы можете использовать 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 }}
  • 0
    HttpRequest.build_absolute_uri(request) эквивалентен request.build_absolute_uri() , не так ли?
  • 0
    @ Марк да, это так.
5

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

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

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

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

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

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

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

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

{{url_parts.domain}}
2

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

  • 0
    Я получаю ошибку, используя request=request . Также не похоже, что запрос задокументирован здесь docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
  • 0
    Я забыл упомянуть, что это доступно только если вы используете REST Framework. Хороший улов, я обновил свой ответ.
Показать ещё 1 комментарий
1

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

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

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

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

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

-3

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

import socket
socket.gethostname()

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

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

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

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

  • 1
    Звучит разумно ...
  • 1
    Вопрос гласит, полный URL
-3

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

  • 3
    Это не включает в себя домен.
  • 0
    домен исключен.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню