Django 템플릿 내 사이트의 도메인 이름을 얻으려면 어떻게해야합니까?


답변:


67

원하는 것은 요청 컨텍스트에 액세스하는 것입니다. RequestContext를 참조하십시오.


140
request.META['HTTP_HOST']도메인을 제공합니다. 템플릿에서는입니다 {{ request.META.HTTP_HOST }}.
— Daniel Roseman

29
요청 메타 데이터 사용에주의하십시오. 브라우저에서 제공되며 스푸핑 될 수 있습니다. 일반적으로 @CarlMeyer가 제안하는 내용을 사용하고 싶을 것입니다.
— Josh

2
내 목적으로는 보안상의 허점이 없습니다.
— Paul Draper

7
허용 된 호스트 설정으로 Django 1.5 이후로 사용하는 것이 안전하다고 생각합니다. docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
— Daniel Backman

8
누군가 "보안 허점"이 무엇인지 자세히 설명 할 수 있습니까? 사용자가 Host:헤더를 스푸핑하고 페이지의 어딘가에서 스푸핑 된 도메인으로 응답을 받으면 어떻게 보안 허점을 만들 수 있습니까? 생성 된 HTML을 가져 와서 자신의 브라우저에 공급하기 전에 자신을 수정하는 사용자와 어떻게 다른지 알 수 없습니다.
— user193130 2016 년

105

실제 HTTP 호스트 헤더를 원하면 @Phsiao의 답변에 대한 Daniel Roseman의 의견을 참조하십시오. 다른 대안은 contrib.sites 프레임 워크를 사용하는 경우 데이터베이스의 사이트에 대한 표준 도메인 이름을 설정할 수 있습니다 (요청 도메인을 올바른 SITE_ID를 사용하여 설정 파일로 매핑하는 것은 사용자가 직접 수행해야하는 것임) 웹 서버 설정). 이 경우 찾고 있습니다 :

from django.contrib.sites.models import Site

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

current_site 객체를 사용하려면 템플릿 컨텍스트에 current_site 객체를 직접 넣어야합니다. 모든 곳에서 사용하는 경우 템플릿 컨텍스트 프로세서로 패키지화 할 수 있습니다.


3
내가 가진 것과 동일한 문제가있는 사람을 명확히하려면 : SITE_ID설정이 id사이트 앱의 현재 사이트 속성 과 같은지 확인합니다 ( id사이트 관리자 패널에서 찾을 수 있음 ). 를 호출 get_current하면 Django가 사용자를 가져 와서 해당 ID를 가진 객체를 데이터베이스에서 SITE_ID반환 Site합니다.
— Dennis Golomazov

이 중 어느 것도 나를 위해 일하지 않습니다. 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
— user251242

86

나는 그 {{ request.get_host }}방법을 발견했다 .


11
이 답변에는 Daniel Roseman 접근 방식과 동일한 문제가 있지만 (스푸핑 될 수 있음) HTTP_X_FORWARDED_HOSTHTTP 헤더 를 고려하기 때문에 HTTP 프록시 또는로드 밸런서를 통해 호스트에 도달하면 더 완벽합니다 .
— furins

4
사용법 : "// {{request.get_host}} / anything / else / you / want"... 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

Carl Meyer를 보완하면 다음과 같은 컨텍스트 프로세서를 만들 수 있습니다.

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의 답변이 매우 유용하다는 것을 알았습니다
— Jose Luis de la Rosa

settings.py에서 context_processors> OPTIONS> 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어쨌든 '사이트'에 액세스하는 것이 없으면 람다가 호출 되지 않으므로 여기에서 사용할 필요가 없습니다 .
— monokrome

를 제거하면 SimpleLazyObject각각 RequestContext이를 호출 get_current_site()하여 SQL 쿼리를 실행합니다. 랩퍼는 변수가 실제로 템플리트에서 사용될 때만 평가되도록합니다.
— vdboor

1
함수이므로 호스트 문자열은 어쨌든 사용되지 않으면 처리되지 않습니다. 따라서 'site_root'에 함수를 할당하면 SimpleLazyObject가 필요하지 않습니다. Django는 사용될 때 함수를 호출합니다. 어쨌든 람다로 필요한 기능을 이미 만들었습니다.
— monokrome

아, 람다 만 작동합니다. 는 SimpleLazyObject이후 정말 필요하지 않은 기능의 재평가 방지하기 위해이 Site객체가 캐시됩니다.
— vdboor

수입은 지금from django.contrib.sites.shortcuts import get_current_site
— Hraban

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

render를 사용하는 경우 RequestContext 를 사용해야합니다 .

request.META['HTTP_HOST']프로덕션을 신뢰하지 마십시오 . 해당 정보는 브라우저에서 제공됩니다. 대신 @CarlMeyer의 답변을 사용하십시오.


이 답변을지지하지만 사용하려고 할 때 오류가 발생했습니다 request.scheme. 아마도 최신 버전의 장고에서만 사용할 수 있습니다.
— 매트 크림

@MattCremeens request.scheme가 Django 1.7에 추가되었습니다.
— S. Kirby

16

{{ request.get_host }}ALLOWED_HOSTS설정 과 함께 사용될 때 HTTP 호스트 헤더 공격으로부터 보호해야 합니다 (Django 1.4.4에 추가됨).

참고 {{ request.META.HTTP_HOST }}동일한 보호가 없습니다. 문서를 참조하십시오 :

ALLOWED_HOSTS

이 장고 사이트가 제공 할 수있는 호스트 / 도메인 이름을 나타내는 문자열 목록입니다. 이것은 HTTP 호스트 헤더 공격 을 방지하기위한 보안 조치입니다. 웹 서버 , 많은 안전한 웹 서버 구성에서도 가능합니다.

... 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/…
— Dennis Golomazov

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
감사합니다. 나는, 템플릿 요청을 수 있도록 context_processors을했다 : django.template.context_processors.request또한 [이 어떻게에 도움] ( simpleisbetterthancomplex.com/tips/2016/07/20/... )
— ionescu77

Vitor Freitas 블로그는 Django 개발자를위한 훌륭한 소스입니다! :)
— Dos

2

당신이 사용하는 경우 "요청"상황에 맞는 프로세서를 하고 사용하는 장고 사이트 프레임 워크를 하고있는 사이트 미들웨어 설치 (즉, 설정은 다음을 포함한다) :

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

이 방법은 어떻습니까? 나를 위해 작동합니다. django-registration 에서도 사용됩니다 .

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)

그러나 그것을 시도하면 정적 URL이있는 경우 작동하지 않는 체계 (안전하다고 간주 됨)를 localhost얻을 수 있습니다 https( http://127.0.0.1유효하지 않습니다 https://127.0.0.1). 따라서 개발 중에는 이상적이지 않습니다.
— ThePhi

0
from django.contrib.sites.models import Site
if Site._meta.installed:
    site = Site.objects.get_current()
else:
    site = RequestSite(request)

-5

당신이 사용할 수있는 {{ protocol }}://{{ domain }}도메인 이름을 얻을 수 있도록 템플릿에서.


@Erwan은 이것이 비표준 요청 컨텍스트 프로세서에 의존한다는 것을 알지 못합니다.
— monokrome

프로토콜과 도메인을 어디에서 정의합니까?
— Jose Luis de la Rosa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.