2009-08-03 6 views
8

おそらく単純な質問と私はちょうど何かが不足していますが、私はアイデアが詰まっています。Djangoクロスサイト逆URL

私はDjangoプロジェクトに、sessions.pyという別個のサイトを提供しており、まったく別のROOT_URLCONFを持っています。 1つのサイトはユーザー登録、認証、およびプロファイル設定を処理し、他のサイト(別のドメイン上)はファイルマネージャーなどとして機能します。サイトは同じDB、メディア、テンプレートを共有しています。すべてのサイトが同じユーザーベースを共有しており、一種の透過的なシングルサインオン/シングルサインオフメカニズムを実装しています。これは、複数のドメインにまたがる1つの大きなサイトのようなものです。

問題は、テンプレートに多くの{% url %}タグがあり、他のサイトでテンプレートを使用しても機能しないということです。そして私は可能な限りURLをハードコーディングしないようにしたいと思います。

たとえば、サイトA(a.example.org)に私はAさんのURLconfで

url('^users/$', 'example.accounts.list_users', name='list_users'), 

エントリを持っています。それで、global_menu.htmlテンプレートでは、私は{% url list_users %}を持っていて、明らかにそれは完全に動作し、結果として "/users/"となります。今

、サイトBは(b.example.org)があります、共通のルック・アンド・フィールを持つためにA.と内部の多くを共有し、私はサイトBで同じglobal_menu.htmlを使用したいと出力に{% url list_users %}をしたい」http://a.example.org/users/ "私はこれを達成する最良の方法は何ですか?

現在、サイトごとに別々のglobal_menu.htmlを使用していますが、これはDRYの原則に違反しており、あまり便利ではありません。そして、はい、Djangoのcontrib.sitesフレームワークを使用しています。別のSITE_IDsettings.pyで定義されていますが、それ以外の場所では実際には使用されていません。

更新:現在、私はオリジナルのものを呼び出すために、urlタグや猿パッチングreverse()を再実装することを考え、そして例外にいくつかの「外国URIリスト」に追加のルックアップを実行しています。このようなものが既に存在するなら、私は聞いて喜んでいるでしょう。

ありがとうございました!

答えて

12

私は私のカスタム関数でdjango.core.urlresolvers.reverseをオーバーライドすることで、それを実装しました::

from django.core import urlresolvers 
from django.conf import settings 

__real_reverse = urlresolvers.reverse 

def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None): 
    try: 
     return __real_reverse(viewname, urlconf, args, kwargs, prefix) 
    except urlresolvers.NoReverseMatch, no_match: 
     external_urlconfs = getattr(settings, 'EXTERNAL_URLCONFS', []) 
     for p, c in external_urlconfs: 
      c = urlresolvers.RegexURLResolver(r'^/', c) 
      try: 
       return p + c.reverse(viewname, *args, **kwargs) 
      except urlresolvers.NoReverseMatch: 
       pass 
     raise no_match 

urlresolvers.reverse = reverse 

たとえば、あなたは、このような方法を使用することができsite_aのURLconfのに対して特異的に逆にします次に、settings.pyのURLconfsを次のように表示します。

ROOT_URLCONF = 'project.urls_a' 

EXTERNAL_URLCONFS = (
    ('http://b.example.com/', 'project.urls_b'), 
) 
0

私は2つの変更を行うことをお勧めします。 (1)既に持っていない場合、テンプレートを共通ディレクトリ(アプリケーションごとではなく)に移動します。 (2)新しく追加されたURL namespacesの機能を調査します。

最初の変更では、共通の基本テンプレートを使用して、さまざまなアプリ/サイトに対して選択的に上書きすることができます。 2つ目は、あなたのURLを「より乾燥した」ものにするかもしれません。

+0

で実行するurls.pyファイル内のコードを配置。 (2)は素晴らしい機能ですが、指摘してくれてありがとうございますが、存在しない名前のURLにはあまり役に立ちません。私はBのURLconfに 'url( 'http:\/\/a \ .example \ .com/users /'、lambda:None、name = 'list_users')のようなものを追加しようとしましたが、私が期待しているように働いています( "/ http:..."を返します)。 – drdaeman

2

はい、独自の反転方法を使用する独自の{% url %}タグを作成する必要があります。

from django.core.urlresolvers import reverse 
import site_a 

def site_a_reverse(viewname, args=None, kwargs=None): 
    # If your sites share the same database, you could get prefix from Site.objects.get(pk=site_a.settings.SITE_ID) 
    prefix = 'http://a.example.com/' # Note, you need the trailing slash 
    reverse(viewname, urlconf=site_a.urls, args=args, kwargs=kwargs, prefix=prefix) 
+0

ありがとうございます!私はmonkey-patchingの 'reverse()'を終わらせました(私のコードを別の答えに入れてください)。 – drdaeman

1

は逆@drdaeman

# -*- coding: utf-8 -*- 
from django.core import urlresolvers 
from django.conf import settings 

__real_reverse = urlresolvers.reverse 


def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None): 
    try: 
     return __real_reverse(viewname, urlconf, args, kwargs, prefix, current_app) 
    except urlresolvers.NoReverseMatch, no_match: 
     external_urlconfs = getattr(settings, 'EXTERNAL_URLCONFS', []) 
     for p, c in external_urlconfs: 
      urlconf = c 
      try: 
       return p + __real_reverse(viewname, urlconf, args, kwargs, prefix, current_app) 
      except urlresolvers.NoReverseMatch: 
       pass 
     raise no_match 

urlresolvers.reverse = reverse 

から同じ設定を使用してDjangoの1.7.xのために上書きI(1)が既に行われている起動

関連する問題