问题
How do I get the domain name of my current site from within a Django template? I've tried looking in the tag and filters but nothing there.
回答1:
I think what you want is to have access to the request context, see RequestContext.
回答2:
If you want the actual HTTP Host header, see Daniel Roseman's comment on @Phsiao's answer. The other alternative is if you're using the contrib.sites framework, you can set a canonical domain name for a Site in the database (mapping the request domain to a settings file with the proper SITE_ID is something you have to do yourself via your webserver setup). In that case you're looking for:
from django.contrib.sites.models import Site
current_site = Site.objects.get_current()
current_site.domain
you'd have to put the current_site object into a template context yourself if you want to use it. If you're using it all over the place, you could package that up in a template context processor.
回答3:
I've discovered the {{ request.get_host }} method.
回答4:
Complementing Carl Meyer, you can make a context processor like this:
module.context_processors.py
from django.conf import settings
def site(request):
return {'SITE_URL': settings.SITE_URL}
local settings.py
SITE_URL = 'http://google.com' # this will reduce the Sites framework db call.
settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
...
"module.context_processors.site",
....
)
templates returning context instance the url site is {{ SITE_URL }}
you can write your own rutine if want to handle subdomains or SSL in the context processor.
回答5:
The variation of the context processor I use is:
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)),
}
The SimpleLazyObject wrapper makes sure the DB call only happens when the template actually uses the site object. This removes the query from the admin pages. It also caches the result.
and include it in the settings:
TEMPLATE_CONTEXT_PROCESSORS = (
...
"module.context_processors.site",
....
)
In the template, you can use {{ site.domain }} to get the current domain name.
edit: to support protocol switching too, use:
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)),
}
回答6:
I know this question is old, but I stumbled upon it looking for a pythonic way to get current domain.
def myview(request):
domain = request.build_absolute_uri('/')[:-1]
# that will build the complete domain: http://foobar.com
回答7:
Quick and simple, but not good for production:
(in a view)
request.scheme # http or https
request.META['HTTP_HOST'] # example.com
request.path # /some/content/1/
(in a template)
{{ request.scheme }} :// {{ request.META.HTTP_HOST }} {{ request.path }}
Be sure to use a RequestContext, which is the case if you're using render.
Don't trust request.META['HTTP_HOST'] in production: that info comes from the browser. Instead, use @CarlMeyer's answer
回答8:
{{ request.get_host }} should protect against HTTP Host header attacks when used together with the ALLOWED_HOSTS setting (added in Django 1.4.4).
Note that {{ request.META.HTTP_HOST }} does not have the same protection. See the docs:
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
Hostheader (orX-Forwarded-HostifUSE_X_FORWARDED_HOSTis enabled) does not match any value in this list, thedjango.http.HttpRequest.get_host()method will raiseSuspiciousOperation.... This validation only applies via
get_host(); if your code accesses the Host header directly fromrequest.METAyou are bypassing this security protection.
As for using the request in your template, the template-rendering function calls have changed in Django 1.8, so you no longer have to handle RequestContext directly.
Here's how to render a template for a view, using the shortcut function render():
from django.shortcuts import render
def my_view(request):
...
return render(request, 'my_template.html', context)
Here's how to render a template for an email, which IMO is the more common case where you'd want the host value:
from django.template.loader import render_to_string
def my_view(request):
...
email_body = render_to_string(
'my_template.txt', context, request=request)
Here's an example of adding a full URL in an email template; request.scheme should get http or https depending on what you're using:
Thanks for registering! Here's your activation link:
{{ request.scheme }}://{{ request.get_host }}{% url 'registration_activate' activation_key %}
回答9:
I use a custom template tag. Add to e.g. <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
Use it in a template like this:
{% load site %}
{% current_domain %}
回答10:
Similar to user panchicore's reply, this is what I did on a very simple website. It provides a few variables and make them available on the template.
SITE_URL would hold a value like example.comSITE_PROTOCOL would hold a value like http or httpsSITE_PROTOCOL_URL would hold a value like http://example.com or https://example.comSITE_PROTOCOL_RELATIVE_URL would hold a value like //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'
Then, on your templates, use them as {{ SITE_URL }}, {{ SITE_PROTOCOL }}, {{ SITE_PROTOCOL_URL }} and {{ SITE_PROTOCOL_RELATIVE_URL }}
回答11:
In a Django template you can do:
<a href="{{ request.scheme }}://{{ request.META.HTTP_HOST }}{{ request.path }}?{{ request.GET.urlencode }}" >link</a>
回答12:
from django.contrib.sites.models import Site
if Site._meta.installed:
site = Site.objects.get_current()
else:
site = RequestSite(request)
回答13:
What about this approach? Works for me. It is also used in 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)
回答14:
You can use {{ protocol }}://{{ domain }} in your templates to get your domain name.
来源:https://stackoverflow.com/questions/1451138/how-can-i-get-the-domain-name-of-my-site-within-a-django-template