如何从Django模板中获取当前站点的域名?我试着寻找标签和过滤器,但那里什么也没有。
如何从Django模板中获取当前站点的域名?我试着寻找标签和过滤器,但那里什么也没有。
Answers:
我认为您想要的是可以访问请求上下文,请参见RequestContext。
Host:
标头并在页面上某处获得带有欺骗域的响应,那将如何创建安全漏洞?我看不出这与用户采用生成的HTML并在将其馈送到其自己的浏览器之前对其进行修改之前不同。
如果需要实际的HTTP Host标头,请参阅Daniel Roseman对@Phsiao答案的评论。另一种选择是,如果您使用的是contrib.sites框架,则可以在数据库中为站点设置一个规范域名(将请求域映射到具有正确SITE_ID的设置文件中,这是您必须通过自己的网络服务器设置)。在这种情况下,您要寻找:
from django.contrib.sites.models import Site
current_site = Site.objects.get_current()
current_site.domain
如果要使用current_site对象,则必须自己将其放在模板上下文中。如果您在各处使用它,则可以将其打包在模板上下文处理器中。
SITE_ID
设置是否等于“ id
网站”应用中当前网站的属性(您可以id
在“网站”管理面板中找到)。当您调用时get_current
,Django会使用SITE_ID
并Site
从数据库返回具有该ID 的对象。
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
我发现了{{ request.get_host }}
方法。
HTTP_X_FORWARDED_HOST
HTTP标头,因此肯定更完整。
request.build_absolute_uri
(docs.djangoproject.com/en/dev/ref/request-response/...)
作为对Carl Meyer的补充,您可以像这样创建一个上下文处理器:
from django.conf import settings
def site(request):
return {'SITE_URL': settings.SITE_URL}
SITE_URL = 'http://google.com' # this will reduce the Sites framework db call.
TEMPLATE_CONTEXT_PROCESSORS = (
...
"module.context_processors.site",
....
)
如果要在上下文处理器中处理子域或SSL,则可以编写自己的例程。
我使用的上下文处理器的变体是:
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
这里使用,因为如果没有人访问“站点”,则不会调用lambda。
SimpleLazyObject
,每个RequestContext
将调用get_current_site()
,并因此执行SQL查询。包装器确保仅在模板中实际使用变量时才评估该变量。
SimpleLazyObject
目的是避免的功能,这是不是真的需要,因为重新评估Site
对象缓存。
from django.contrib.sites.shortcuts import get_current_site
我知道这个问题很老,但是我偶然发现了这个问题,寻找一种获取当前域的pythonic方法。
def myview(request):
domain = request.build_absolute_uri('/')[:-1]
# that will build the complete domain: http://foobar.com
build_absolute_uri
记录在这里。
快速简单,但不适用于生产:
(在视图中)
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,如果使用render,就是这种情况。
不要相信request.META['HTTP_HOST']
生产:该信息来自浏览器。而是使用@CarlMeyer的答案
request.scheme
。也许仅在django的较新版本中可用。
request.scheme
是在Django 1.7中添加的。
{{ request.get_host }}
与ALLOWED_HOSTS
设置(在Django 1.4.4中添加)一起使用时,应该可以防止HTTP Host标头攻击。
请注意,{{ request.META.HTTP_HOST }}
没有相同的保护。见文档:
ALLOWED_HOSTS
代表此Django站点可以服务的主机/域名的字符串列表。这是一种安全措施,可以防止HTTP Host标头攻击,即使在许多看似安全的Web服务器配置下也可能发生这种攻击。
...如果
Host
标头(或者X-Forwarded-Host
如果USE_X_FORWARDED_HOST
使能)不匹配,在此列表中的任何值,该django.http.HttpRequest.get_host()
方法将提高SuspiciousOperation
。...此验证仅通过进行
get_host()
;如果您的代码直接从request.META
您访问Host标头,则绕过此安全保护措施。
至于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 %}
我使用自定义模板标签。添加到例如<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 %}
get_current
是一种记录方法:docs.djangoproject.com/en/dev/ref/contrib/sites/...
'http://%s'
在https
连接的情况下可能是一个问题;在这种情况下,方案不是动态的。
与用户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 }}
在Django模板中,您可以执行以下操作:
<a href="{{ request.scheme }}://{{ request.META.HTTP_HOST }}{{ request.path }}?{{ request.GET.urlencode }}" >link</a>
django.template.context_processors.request
也[这如何做帮助(simpleisbetterthancomplex.com/tips/2016/07/20/...)
如果您使用“请求”上下文处理器,并且正在使用Django sites框架,并且安装了Site中间件(即您的设置包括以下内容):
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}}
那这种方法呢?为我工作。它也用于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)
localhost
会为您提供一个https
方案(它被认为是安全的),如果您具有静态url(仅http://127.0.0.1
有效,则不是https://127.0.0.1
),该方案将不起作用。因此,当仍在开发中时,它并不理想。
from django.contrib.sites.models import Site
if Site._meta.installed:
site = Site.objects.get_current()
else:
site = RequestSite(request)
您可以{{ protocol }}://{{ domain }}
在模板中使用来获取域名。
request.META['HTTP_HOST']
给您域名。在模板中应该是{{ request.META.HTTP_HOST }}
。