Djangoテンプレート内で自分のサイトのドメイン名を取得するにはどうすればよいですか?


回答:


67

私はあなたが望むのはリクエストコンテキストにアクセスできることだと思います。RequestContextを見てください。


140
request.META['HTTP_HOST']ドメインを提供します。テンプレートではそうなります{{ request.META.HTTP_HOST }}
ダニエルローズマン

29
リクエストメタデータの使用には注意してください。ブラウザからのものであり、なりすましの可能性があります。一般的には、@ CarlMeyerが以下に提案するものを使用することをお勧めします。
ジョシュ

2
私の目的では、これにはセキュリティホールはありません。
ポールドレイパー

7
Django 1.5では許可されたホストが設定されているので、安全に使用できます。docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
Daniel Backman

8
誰かが「セキュリティホール」とは何かについて詳しく説明できますか?ユーザーがHost:ヘッダーをスプーフィングし、ページのどこかにスプーフィングされたドメインで応答を受け取った場合、どのようにしてセキュリティホールが発生しますか?ユーザーが生成されたHTMLを取得して自分のブラウザーにフィードする前に自分自身を変更することと、それがどのように異なるかはわかりません。
user193130

105

実際のHTTPホストヘッダーが必要な場合は、@ Phsiaoの回答に関するDaniel Rosemanのコメントを参照してください。もう1つの方法は、contrib.sitesフレームワークを使用している場合、データベースのサイトの正規ドメイン名を設定できます(リクエストドメインを適切なSITE_IDを含む設定ファイルにマッピングすることは、ウェブサーバーの設定)。その場合、あなたは探しています:

from django.contrib.sites.models import Site

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

使用する場合は、current_siteオブジェクトを自分でテンプレートコンテキストに配置する必要があります。あらゆる場所で使用している場合は、テンプレートコンテキストプロセッサにパッケージ化できます。


3
私と同じ問題を抱えている人を明確にするには、SITE_ID設定がidサイトアプリの現在のサイトの属性と等しいことを確認します(idサイトの管理パネルにあります)。を呼び出すとget_current、Djangoはを受け取り、データベースからそのID SITE_IDSiteオブジェクトを返します。
Dennis Golomazov 2013

これらのどれも私のために働きません。 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プロキシまたはロードバランサーを介してホストに到達すると、より完全になることに注意してください。
風鈴14年

4
使用法: "// {{request.get_host}} / anything / else / you / want" ...必ずALLOWED_HOSTS設定を入力してください(docs.djangoproject.com/en/1.5/ref/settings/#allowedを参照) -hosts)。
セス

3
@Sethはより有効に活用するrequest.build_absolute_uridocs.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}

ローカル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を処理する場合は、独自のルーティンを作成できます。


私はこの解決策を試しましたが、同じアプリケーションに複数のサブドメインがある場合、それは実用的ではありません。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何も「サイト」にアクセスしない場合はラムダが呼び出されないため、ここで使用する必要はありません。
モノクローム2014

を削除するとSimpleLazyObject、それぞれRequestContextがを呼び出すget_current_site()ため、SQLクエリが実行されます。ラッパーは、変数がテンプレートで実際に使用されたときにのみ評価されるようにします。
vdboor 2014

1
これは関数なので、とにかく使用しない限り、ホスト文字列は処理されません。したがって、「site_root」に関数を割り当てるだけでよく、SimpleLazyObjectは必要ありません。Djangoは、使用時に関数を呼び出します。とにかく、ここでラムダを使用して必要な関数をすでに作成しました。
モノクローム2014

ええ、ラムダだけが機能します。これSimpleLazyObjectは関数の再評価を回避するためにありSiteます。オブジェクトがキャッシュされるため、これは実際には必要ありません。
vdboor 2014

インポートは現在from django.contrib.sites.shortcuts import get_current_site
Hraban

22

私はこの質問が古いことを知っていますが、現在のドメインを取得するpythonicの方法を探して偶然見つけました。

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

4
build_absolute_uriここに記載されています
Philipp Zedler、2015

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。おそらく、djangoの新しいバージョンでのみ使用できます。
Matt Cremeens、2018

@MattCremeens request.schemeはDjango 1.7で追加されました。
S.カービー

16

{{ request.get_host }}ALLOWED_HOSTS設定(Django 1.4.4で追加)と併用すると、HTTPホストヘッダー攻撃から保護されます。

{{ request.META.HTTP_HOST }}は同じ保護機能がないことに注意してください。ドキュメントを参照してください:

ALLOWED_HOSTS

このDjangoサイトが提供できるホスト/ドメイン名を表す文字列のリスト。これは、HTTPホストヘッダー攻撃を防ぐためのセキュリティ対策です。これは、多くの安全なWebサーバー構成でも可能です。

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

EMOのテンプレートをレンダリングする方法は次のとおりです。この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.schemehttphttps使用しているものを取得するか、依存する必要があります。

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

このアプローチには特定の欠点がありますか?リクエストごとのSite dbの呼び出しは別として。
kicker86

@ kicker86わからない。get_current文書化の方法は次のとおりです。docs.djangoproject.com/en/dev/ref/contrib/sites/...
デニスGolomazov

3
'http://%s'https接続の場合は問題になる可能性があります。この場合、スキームは動的ではありません。
破損したオーガニック

4

ユーザーpanchicoreの返信と同様に、これは私が非常に単純なWebサイトで行ったことです。いくつかの変数を提供し、それらをテンプレートで使用できるようにします。

SITE_URLのような値を保持するような値example.com
SITE_PROTOCOLを保持するhttphttps
SITE_PROTOCOL_URL、のような値を保持するhttp://example.comhttps://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開発者にとって素晴らしい情報源です!:)
ドス

2

あなたが使用している場合は、「要求」コンテキストプロセッサを、そして使用しているDjangoのサイトのフレームワークを、と持っているサイトのミドルウェアがインストールされ(すなわち、あなたの設定には、これらを含めます):

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)

しかし、でそれをしようとすると、localhostあなたを取得しますhttps(これは安全と考えています)あなたは、静的なURLを持っている場合は動作しませんどのスキームを(のみhttp://127.0.0.1、有効ではありませんhttps://127.0.0.1)。したがって、まだ開発中の場合は理想的ではありません。
ThePhi


-5

{{ protocol }}://{{ domain }}テンプレートでを使用して、ドメイン名を取得できます。


@Erwanがこれが非標準のリクエストコンテキストプロセッサに依存していることに気付かないと思います。
モノクローム2014

これを機能させることができませんでした。プロトコルとドメインはどこで定義しますか?
デラロサ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.