Як я можу отримати доменне ім’я свого сайту в шаблоні Django?


Відповіді:


67

Я думаю, що вам потрібно отримати доступ до контексту запиту, див. RequestContext.


140
request.META['HTTP_HOST']дає вам домен. У шаблоні це було б {{ request.META.HTTP_HOST }}.
Даніель Роузмен

29
Будьте обережні, використовуючи метадані запиту. Він надходить із браузера і може бути підроблений. Взагалі, ви, ймовірно, захочете піти з запропонованим нижче @CarlMeyer.
Джош

2
Для моїх цілей у цьому відсутній отвір для безпеки.
Пол Дрейпер

7
Я думаю, оскільки Django 1.5 з дозволеними налаштуваннями хостів це безпечно у використанні. docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
Daniel Backman

8
Чи може хтось детальніше розібратися, що таке "дірка безпеки"? Якщо користувач підробляє Host:заголовок і отримує відповідь із підробленим доменом десь на сторінці, як це створює дірку безпеки? Я не бачу, чим це відрізняється від того, що користувач приймає створений HTML і модифікує себе перед тим, як подавати його у свій веб-переглядач.
користувач193130

105

Якщо ви хочете фактичний заголовок HTTP Host, дивіться коментар Даніела Роузмена щодо відповіді @ Phsiao. Інша альтернатива - якщо ви використовуєте структуру contrib.sites , ви можете встановити канонічне доменне ім’я для сайту в базі даних (зіставлення домену запиту у файл налаштувань із належним SITE_ID - це те, що вам потрібно зробити самостійно через ваш налаштування веб-сервера). У такому випадку ви шукаєте:

from django.contrib.sites.models import Site

current_site = Site.objects.get_current()
current_site.domain

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


3
Щоб уточнити, хто має ті самі проблеми, як у мене: перевірте, чи ваш SITE_IDпараметр дорівнює idатрибуту поточного сайту в додатку Сайти (ви можете знайти його idна панелі адміністратора сайтів). Коли ви телефонуєте get_current, Django бере ваш SITE_IDі повертає Siteоб’єкт із цим ідентифікатором із бази даних.
Денніс Голомазов

Жодне з цих не працює для мене. print("get_current_site: ", get_current_site(request)) print("absolute uri: ", request.build_absolute_uri()) print("HTTP_HOST: ", request.META['HTTP_HOST']) get_current_site: localhost:8001 absolute uri: http://localhost:8001/... HTTP_HOST: localhost:8001
користувач251242

86

Я відкрив {{ request.get_host }}метод.


11
Зверніть увагу, що ця відповідь має ті ж самі питання, що і підхід Даніела Роузмена (він може бути підроблений), але це, безумовно, більш повно, коли хост буде досягнуто через проксі-сервер HTTP або балансир завантаження, оскільки він враховує HTTP_X_FORWARDED_HOSTHTTP-заголовок.
furins

4
Використання: "// {{request.get_host}} / все / ще / ти / хочеш" ... Обов’язково заповніть налаштування ALLOWED_HOSTS (див. Docs.djangoproject.com/en/1.5/ref/settings/#allowed -хости ).
Сет

3
@Seth краще використовувати request.build_absolute_uri( docs.djangoproject.com/en/dev/ref/request-response/… )
MrKsn

60

Доповнюючи Карла Мейєра, ви можете зробити контекстний процесор таким чином:

module.context_processors.py

from django.conf import settings

def site(request):
    return {'SITE_URL': settings.SITE_URL}

локальні настройки.py

SITE_URL = 'http://google.com' # this will reduce the Sites framework db call.

settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
 )

шаблони, що повертають екземпляр контексту, URL-адресою {{SITE_URL}}

ви можете написати власну рутину, якщо хочете обробляти піддомени або SSL в контекстовому процесорі.


Я спробував це рішення, але якщо у вас є кілька субдоменів для однієї програми, це не практично, я знайшов дуже корисну відповідь від danbruegge
Хосе Луїс де ла Роза

в settings.py ви повинні представити свій контекстний процесор у context_processors> ВАРІАНТИ> TEMPLATES
yas17

24

Варіант контекстного процесора, який я використовую, є:

from django.contrib.sites.shortcuts import get_current_site
from django.utils.functional import SimpleLazyObject


def site(request):
    return {
        'site': SimpleLazyObject(lambda: get_current_site(request)),
    }

SimpleLazyObjectОбгортка переконується виклик DB відбувається тільки тоді , коли шаблон фактично використовує siteоб'єкт. Це видаляє запит зі сторінок адміністратора. Це також кешує результат.

і включіть його в налаштування:

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
)

У шаблоні ви можете використовувати {{ site.domain }}поточне ім'я домену.

редагувати: для підтримки перемикання протоколів також використовуйте:

def site(request):
    site = SimpleLazyObject(lambda: get_current_site(request))
    protocol = 'https' if request.is_secure() else 'http'

    return {
        'site': site,
        'site_root': SimpleLazyObject(lambda: "{0}://{1}".format(protocol, site.domain)),
    }

Тут вам не потрібно використовувати SimpleLazyObject, тому що лямбда не буде називатися, якщо все-таки нічого не звертається до "сайту".
монокром

Якщо ви видалите SimpleLazyObject, кожен RequestContextвикличе get_current_site(), а тому виконає SQL-запит. Обгортка гарантує, що змінна оцінюється лише тоді, коли вона фактично використовується в шаблоні.
vdboor

1
Оскільки це функція, хост-рядок не буде оброблятися, якщо все одно не буде використаний. Отже, ви можете просто призначити функцію 'site_root', і вам не потрібен SimpleLazyObject. Django викличе функцію, коли вона використовується. Ви вже створили необхідну функцію з лямбда тут.
монокром

Ага так, тільки лямбда працювала б. SimpleLazyObjectЄ , щоб уникнути повторної оцінки функції, яка не дійсно необхідно , так як Siteоб'єкт в кеші.
vdboor

Зараз імпортfrom django.contrib.sites.shortcuts import get_current_site
Грабан

22

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

def myview(request):
    domain = request.build_absolute_uri('/')[:-1]
    # that will build the complete domain: http://foobar.com

4
build_absolute_uriдокументований тут .
Philipp Zedler

19

Швидкий і простий, але не корисний для виробництва:

(на виду)

    request.scheme               # http or https
    request.META['HTTP_HOST']    # example.com
    request.path                 # /some/content/1/

(у шаблоні)

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

Обов’язково використовуйте RequestContext , у тому випадку, якщо ви використовуєте візуалізацію .

Не довіряйте request.META['HTTP_HOST']виробництву: ця інформація надходить із браузера. Замість цього скористайтеся відповіддю @ CarlMeyer


Я підтримую цю відповідь, але при спробі використання я отримав помилку request.scheme. Можливо, доступний лише в новіших версіях джанго.
Метт Кременс

@MattCremeens request.schemeдодано в Django 1.7.
С. Кірбі

16

{{ request.get_host }}має захищати від атаки заголовка HTTP Host при використанні разом із ALLOWED_HOSTSналаштуваннями (додано в Django 1.4.4).

Зауважте, що {{ request.META.HTTP_HOST }}не має однакового захисту. Дивіться документи :

ALLOWED_HOSTS

Список рядків, що представляють імена хостів / доменів, якими може слугувати цей сайт Django. Це захід безпеки для запобігання атакам заголовка HTTP Host , які можливі навіть у багатьох конфігураціях веб-сервера.

... Якщо Hostзаголовок (або X-Forwarded-Hostякщо USE_X_FORWARDED_HOSTвін включений) не відповідає жодному значенню у цьому списку, django.http.HttpRequest.get_host()метод підвищиться SuspiciousOperation.

... Ця перевірка застосовується лише через get_host(); якщо ваш код отримує доступ до заголовка хоста безпосередньо від request.METAвас, обходять цей захист.


Що стосується використання requestу вашому шаблоні, в Django 1.8 змінилися дзвінки функції передавання шаблонів , тому вам більше не доведеться RequestContextбезпосередньо звертатися .

Ось як надати шаблон для подання за допомогою функції швидкого доступу render():

from django.shortcuts import render

def my_view(request):
    ...
    return render(request, 'my_template.html', context)

Ось як надати шаблон для електронної пошти, який IMO - це найпоширеніший випадок, коли ви хочете значення хосту:

from django.template.loader import render_to_string

def my_view(request):
    ...
    email_body = render_to_string(
        'my_template.txt', context, request=request)

Ось приклад додавання повної URL-адреси в шаблон електронної пошти; request.scheme має отримати httpабо httpsзалежно від того, що ви використовуєте:

Thanks for registering! Here's your activation link:
{{ request.scheme }}://{{ request.get_host }}{% url 'registration_activate' activation_key %}

10

Я використовую спеціальний тег шаблону. Додайте до <your_app>/templatetags/site.py:

# -*- coding: utf-8 -*-
from django import template
from django.contrib.sites.models import Site

register = template.Library()

@register.simple_tag
def current_domain():
    return 'http://%s' % Site.objects.get_current().domain

Використовуйте його в такому шаблоні:

{% load site %}
{% current_domain %}

Чи є якийсь мінус у цього підходу? Крім дзвінка на сайт db за кожним запитом.
kicker86

@ kicker86 Я не знаю жодного. get_current- це документально підтверджений метод: docs.djangoproject.com/en/dev/ref/contrib/sites/…
Денніс Голомазов

3
'http://%s'може бути проблемою у випадку httpsпідключення; схема в цьому випадку не динамічна.
Пошкоджені органічні

4

Подібно до відповіді користувача panchicore, це те, що я робив на дуже простому веб-сайті. Він надає кілька змінних та робить їх доступними у шаблоні.

SITE_URLматиме значення, подібне до example.com
SITE_PROTOCOLтакого, якhttp або https
SITE_PROTOCOL_URLмістило б таке значення, як http://example.comабо https://example.com
SITE_PROTOCOL_RELATIVE_URLмістило б таке значення //example.com.

module / context_processors.py

from django.conf import settings

def site(request):

    SITE_PROTOCOL_RELATIVE_URL = '//' + settings.SITE_URL

    SITE_PROTOCOL = 'http'
    if request.is_secure():
        SITE_PROTOCOL = 'https'

    SITE_PROTOCOL_URL = SITE_PROTOCOL + '://' + settings.SITE_URL

    return {
        'SITE_URL': settings.SITE_URL,
        'SITE_PROTOCOL': SITE_PROTOCOL,
        'SITE_PROTOCOL_URL': SITE_PROTOCOL_URL,
        'SITE_PROTOCOL_RELATIVE_URL': SITE_PROTOCOL_RELATIVE_URL
    }

settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    "module.context_processors.site",
    ....
 )

SITE_URL = 'example.com'

Потім на шаблонах, використовувати їх як {{ SITE_URL }}, {{ SITE_PROTOCOL }}, {{ SITE_PROTOCOL_URL }}і{{ SITE_PROTOCOL_RELATIVE_URL }}


2

У шаблоні Django ви можете:

<a href="{{ request.scheme }}://{{ request.META.HTTP_HOST }}{{ request.path }}?{{ request.GET.urlencode }}" >link</a>

1
Це працювало для мене дякую. Мені довелося ввімкнути запит у TEMPLATES, context_processors:, django.template.context_processors.requestтакож [це як допомогло] ( simpleisbetterthancomplex.com/tips/2016/07/20/… )
ionescu77

Погодьтеся, блог Vitor Freitas - чудове джерело для розробників Django! :)
Dos

2

Якщо ви використовуєте контекстний процесор "запит" і використовуєте рамку сайтів Django , і встановлено проміжне програмне забезпечення сайту (тобто ваші налаштування включають такі):

INSTALLED_APPS = [
    ...
    "django.contrib.sites",
    ...
]

MIDDLEWARE = [
    ...
     "django.contrib.sites.middleware.CurrentSiteMiddleware",
    ...
]

TEMPLATES = [
    {
        ...
        "OPTIONS": {
            "context_processors": [
                ...
                "django.template.context_processors.request",
                ...
            ]
        }
    }
]

... тоді у вас буде requestоб’єкт доступний у шаблонах, і він буде містити посилання на поточний Siteдля запиту як request.site. Потім ви можете отримати домен у шаблоні за допомогою:

    {{request.site.domain}}

1

Що з таким підходом? Працює для мене. Він також використовується при реєстрації джанго .

def get_request_root_url(self):
    scheme = 'https' if self.request.is_secure() else 'http'
    site = get_current_site(self.request)
    return '%s://%s' % (scheme, site)

Але якщо спробувати це, localhostви отримаєте httpsсхему (Це вважається безпечною), яка не працюватиме, якщо у вас є статичний URL-адреса ( http://127.0.0.1діє лише , не так https://127.0.0.1). Тож це не ідеально, коли ще в розвитку.
ThePhi


-5

Ви можете використовувати {{ protocol }}://{{ domain }}у своїх шаблонах для отримання вашого доменного імені.


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

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