如何从Django模板中获取当前站点的域名?我试着在标签和过滤器中寻找,但没有什么。


当前回答

补充Carl Meyer,你可以做一个这样的上下文处理器:

module.context_processors.py

from django.conf import settings

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

当地settings.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,可以编写自己的例程。

其他回答

我使用的上下文处理器的变化是:

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调用。这将从管理页面中删除查询。它还缓存结果。

并将其包含在设置中:

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

正如@furins的回复中提到的,代理服务器可能存在问题。我在使用Apache和uWSGI - request时发现了这一点。Get_host或request。Build_absolute_uri将返回代理主机(127.0.0.1:9191…)。

然而,有人已经发布了一个有用的指南来解决这个问题:

https://ubuntu.com/blog/django-behind-a-proxy-fixing-absolute-urls

虽然这是一个相对较老的答案,但它仍然与django 3.2和python 3.9相关。

为了防止这个答案在未来消失,以下是它的要点:

settings.py

# Setup support for proxy headers
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

apache.conf

<VirtualHost *:443>
    ...
    RequestHeader set X-Forwarded-Proto 'https' env=HTTPS

    ProxyPass / http://10.0.0.3/
    ProxyPassReverse / http://10.0.0.3/
    ...
</VirtualHost>

使用这些设置请求。Get_host和request。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,如果你使用渲染就是这样。

不要相信请求。生产中的META['HTTP_HOST']:该信息来自浏览器。相反,请使用@CarlMeyer的答案

{{请求。get_host}}在和ALLOWED_HOSTS设置(在Django 1.4.4中添加)一起使用时,可以防止HTTP主机头攻击。

注意{{request.META。HTTP_HOST}}没有相同的保护。查看文档:

ALLOWED_HOSTS A list of strings representing the host/domain names that this Django site can serve. This is a security measure to prevent HTTP Host header attacks, which are possible even under many seemingly-safe web server configurations. ... If the Host header (or X-Forwarded-Host if USE_X_FORWARDED_HOST is enabled) does not match any value in this list, the django.http.HttpRequest.get_host() method will raise SuspiciousOperation. ... This validation only applies via get_host(); if your code accesses the Host header directly from request.META you are bypassing this security protection.


至于在模板中使用请求,在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的示例;请求。Scheme应该获得HTTP或HTTPS,这取决于您使用的是什么:

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

补充Carl Meyer,你可以做一个这样的上下文处理器:

module.context_processors.py

from django.conf import settings

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

当地settings.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,可以编写自己的例程。