Bir Django şablonunda sitemin alan adını nasıl alabilirim?


Yanıtlar:


67

İstediğiniz şey, istek bağlamına erişim sağlamak olduğunu düşünüyorum, bkz. RequestContext.


140
request.META['HTTP_HOST']size alan adını verir. Bir şablonda olurdu {{ request.META.HTTP_HOST }}.
Daniel Roseman

29
İstek meta verilerini kullanırken dikkatli olun. Bir tarayıcıdan geliyor ve sahte olabilir. Genel olarak, muhtemelen @CarlMeyer tarafından önerilenlerle gitmek isteyeceksiniz.
Josh

2
Benim amacım için bunun bir güvenlik açığı yok.
Paul Draper

7
Sanırım, izin verilen ana bilgisayar ayarı ile Django 1.5 beri kullanmak güvenli. docs.djangoproject.com/tr/1.5/ref/settings/#allowed-hosts
Daniel Backman

8
Birisi "güvenlik açığı" nı açıklayabilir mi? Kullanıcı Host:üstbilgi sahtekarlığı yapar ve sahtekarlık alan adıyla sayfanın herhangi bir yerinde yanıt alırsa, bu nasıl güvenlik açığı oluşturur? Bunun, oluşturulan HTML'yi alan ve kendi tarayıcısına beslemeden önce kendini değiştiren bir kullanıcıdan nasıl farklı olduğunu görmüyorum.
user193130

105

Gerçek HTTP Ana Bilgisayar başlığını istiyorsanız, Daniel Roseman'ın @ Phsiao'nun cevabı hakkındaki yorumuna bakın. Diğer bir alternatif, katkı.sites çerçevesini kullanıyorsanız, veritabanındaki bir Site için kanonik bir alan adı ayarlayabilirsiniz (istek alanını uygun SITE_ID değerine sahip bir ayar dosyasıyla eşleştirmek, web sunucusu kurulumu). Bu durumda:

from django.contrib.sites.models import Site

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

kullanmak istiyorsanız current_site nesnesini bir şablon bağlamına koymanız gerekir. Her yerde kullanıyorsanız, bunu bir şablon bağlamı işlemcisinde paketleyebilirsiniz.


3
Benimle aynı sorunları olan birini açıklığa kavuşturmak için: SITE_IDayarınızın idSites uygulamasındaki mevcut sitenin özelliğine eşit olup olmadığını kontrol edin ( idSiteler yönetici panelinde bulabilirsiniz ). Aradığınızda get_current, Django nesnenizi alır SITE_IDve Sitebu kimliğe sahip nesneyi veritabanından döndürür .
Dennis Golomazov

Bunların hiçbiri benim için çalışmıyor. 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 }}Yöntemi keşfettim .


11
Bu cevabın Daniel Roseman yaklaşımıyla aynı sorunlara sahip olduğunu (sahte olabileceğini) unutmayın, ancak HTTP_X_FORWARDED_HOSTHTTP üstbilgisini hesaba kattığı için ana bilgisayara bir HTTP proxy veya yük dengeleyici aracılığıyla ulaşıldığında kesinlikle daha eksiksizdir .
furins

4
Kullanım: "// {{request.get_host}} / herhangi bir şey / başka / istediğiniz / istediğiniz" ... ALLOWED_HOSTS ayarınızı doldurduğunuzdan emin olun (bkz. Docs.djangoproject.com/en/1.5/ref/settings/#allowed -hosts ).
Seth

3
@ Kullanmak daha iyi request.build_absolute_uri( docs.djangoproject.com/en/dev/ref/request-response/… )
MrKsn

60

Carl Meyer'ı tamamlayarak, aşağıdaki gibi bir bağlam işlemcisi yapabilirsiniz:

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",
    ....
 )

url sitesinin bağlam örneği döndüren şablonlar {{SITE_URL}}

bağlam işlemcisinde alt alan adlarını veya SSL'yi işlemek istiyorsanız kendi rutininizi yazabilirsiniz.


Bu çözümü denedim ama aynı uygulama için birkaç alt alanınız varsa pratik değil, danbruegge tarafından cevap çok yararlı buldum
Jose Luis de la Rosa

settings.py'de, bağlam işlemcinizi context_processors> OPTIONS> TEMPLATES
yas17 öğesinde

24

Kullandığım bağlam işlemcisinin varyasyonu:

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

SimpleLazyObjectSarıcı şablonu aslında kullandığında DB arama yalnızca olmuyor emin olur sitenesneyi. Bu, sorguyu yönetici sayfalarından kaldırır. Ayrıca sonucu önbelleğe alır.

ve ayarlara ekleyin:

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

Şablonda, {{ site.domain }}geçerli alan adını almak için kullanabilirsiniz .

edit: protokol geçişini de desteklemek için şunu kullanın:

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

SimpleLazyObjectBurada kullanmanıza gerek yok, çünkü yine de hiçbir şey 'siteye' erişemezse lambda çağrılmaz.
monokrome

Kaldırırsanız SimpleLazyObject, her biri RequestContextçağırır get_current_site()ve bu nedenle bir SQL sorgusu yürütür. Sarıcı, değişkenin yalnızca şablonda gerçekten kullanıldığında değerlendirilmesini sağlar.
vdboor

1
Bu bir işlev olduğundan, zaten kullanılmadıkça ana bilgisayar dizesi işlenmez. Yani, 'site_root' a bir işlev atayabilirsiniz ve SimpleLazyObject gerekmez. Django işlevi kullanıldığında işlevi çağıracaktır. Zaten burada bir lambda ile gerekli işlevi yarattınız.
monokrome

Ah evet, sadece bir lambda çalışırdı. SimpleLazyObjectÇünkü gerçekten gerekli değildir fonksiyonun yeniden değerlendirilmesini önlemek için orada Sitenesne önbelleğe alınır.
vdboor

İthalat şu andafrom django.contrib.sites.shortcuts import get_current_site
Hraban

22

Bu sorunun eski olduğunu biliyorum, ama mevcut etki alanı elde etmek için pythonic bir yol arayan tökezledi.

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

4
build_absolute_uriburada belgelenmiştir .
Philipp Zedler

19

Hızlı ve basit, ancak üretim için iyi değil:

(bir görünümde)

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

(bir şablonda)

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

Bir kullandığınızdan emin olun RequestContext kullandığınız takdirde böyledir, işlemek .

request.META['HTTP_HOST']Üretime güvenmeyin : bu bilgi tarayıcıdan gelir. Bunun yerine, @ CarlMeyer'ın cevabını kullanın


Bu cevabı iptal ediyorum ama kullanmaya çalışırken bir hata aldım request.scheme. Belki de sadece django'nun yeni sürümlerinde mevcuttur.
Matt Cremeens

@MattCremeens request.scheme, Django 1.7'ye eklendi.
S. Kirby

16

{{ request.get_host }}ALLOWED_HOSTSayarla birlikte kullanıldığında HTTP Ana Bilgisayar üstbilgi saldırılarına karşı koruma sağlamalıdır (Django 1.4.4'te eklenmiştir).

{{ request.META.HTTP_HOST }}Aynı korumaya sahip olmadığını unutmayın . Belgelere bakın :

ALLOWED_HOSTS

Bu Django sitesinin sunabileceği ana bilgisayar / etki alanı adlarını temsil eden dizelerin listesi. Bu, görünüşte güvenli olan birçok web sunucusu yapılandırmasında bile mümkün olan HTTP Ana Bilgisayar üstbilgisi saldırılarını önlemek için bir güvenlik önlemidir .

... Eğer Host(veya başlığa X-Forwarded-Hosteğer USE_X_FORWARDED_HOSTbu listedeki herhangi bir değer uymuyor etkindir), django.http.HttpRequest.get_host()yöntem yükseltecektir SuspiciousOperation.

... Bu doğrulama sadece get_host(); kodunuz doğrudan request.METAsizden Host başlığına erişiyorsa bu güvenlik korumasını atlıyorsunuz demektir.


requestŞablonunuzda kullanılmaya gelince , Django 1.8'de şablon oluşturma işlevi çağrıları değişti , bu yüzden artık RequestContextdoğrudan işlemek zorunda değilsiniz .

Kısayol işlevini kullanarak bir görünüm için şablonun nasıl oluşturulacağı aşağıda açıklanmıştır render():

from django.shortcuts import render

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

Bir e-posta için nasıl şablon oluşturulacağı aşağıda açıklanmaktadır: IMO, ana makine değerini istediğiniz daha yaygın bir durumdur:

from django.template.loader import render_to_string

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

Aşağıda, bir e-posta şablonuna tam URL ekleme örneği; request.scheme almalısınız httpveya httpskullandığınız hangi bağlı:

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

10

Özel bir şablon etiketi kullanıyorum. Örneğin ekle <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

Şunun gibi bir şablonda kullanın:

{% load site %}
{% current_domain %}

Bu yaklaşımın belirli bir dezavantajı var mı? Siteye çağrı dışında her istek üzerine db.
kicker86

@ kicker86 Hiç bilmiyorum. get_currentbelgelenmiş bir yöntemdir: docs.djangoproject.com/en/dev/ref/contrib/sites/…
Dennis Golomazov

3
'http://%s'httpsbağlantı durumunda bir sorun olabilir ; şema bu durumda dinamik değildir.
Hasarlı Organik

4

Kullanıcı panchicore'un cevabına benzer şekilde, bu çok basit bir web sitesinde yaptığım şey. Birkaç değişken sağlar ve bunları şablonda kullanılabilir hale getirir.

SITE_URLgibi bir değer yapacağını example.com
SITE_PROTOCOLgibi bir değeri yapacağını http veya https
SITE_PROTOCOL_URLbenzeri bir değeri yapacağını http://example.comveya https://example.com
SITE_PROTOCOL_RELATIVE_URLbenzeri bir değeri yapacağını //example.com.

modül / 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'

Ardından, şablonlara olarak bunları kullanmak {{ SITE_URL }}, {{ SITE_PROTOCOL }}, {{ SITE_PROTOCOL_URL }}ve{{ SITE_PROTOCOL_RELATIVE_URL }}


2

Bir Django şablonunda şunları yapabilirsiniz:

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

1
Bu benim için çalıştı, teşekkürler. TEMPLATES, context_processors:, django.template.context_processors.requestda [bu nasıl yardımcı oldu] isteğini etkinleştirmek zorunda kaldım ( simpleisbetterthancomplex.com/tips/2016/07/20/… )
ionescu77 25:19

Kabul, Vitor Freitas blogu Django geliştiricileri için harika bir kaynak! :)
Dos

2

Eğer kullanırsanız "istek" bağlam işlemci ve kullandığınız Django siteleri çerçeve ve sahip Sitesi katman yüklü (yani ayarlarınız bu ekleyin):

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

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

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

... sonra requestnesnenin şablonlarda kullanılabilir Siteolmasını sağlar ve istek için geçerli olana bir başvuru içerir request.site. Ardından, aşağıdakileri içeren bir şablondaki etki alanını alabilirsiniz:

    {{request.site.domain}}

1

Bu yaklaşım ne olacak? Benim için çalışıyor. Django kaydında da kullanılır .

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)

Ancak bunu denemek , statik URL'niz varsa işe yaramayacak localhostbir httpsşema (Güvenli olarak kabul edilir) alacaktır (sadece http://127.0.0.1geçerlidir, değil https://127.0.0.1). Bu yüzden hala geliştirme aşamasında değil.
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 }}Alan adınızı almak için şablonlarınızda kullanabilirsiniz .


@Erwan'ın bunun standart dışı bir istek bağlam işlemcisine bağlı olduğunu fark ettiğini düşünmüyorum.
monokrome

Bu işi yapamadım, protokolü ve etki alanını nerede tanımlıyorsunuz?
Jose Luis de la Rosa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.