Django跨站点反向URL

时间:2009-08-03 10:55:08

标签: django url templates dry reverse

可能是一个简单的问题,我只是遗漏了一些东西,但是我的想法很难理解。

我有Django项目为几个具有不同sessions.py和完全不同ROOT_URLCONF的网站提供服务。一个站点处理用户注册,身份验证和配置文件设置,其他站点(在另一个域上)充当文件管理器等。站点共享相同的数据库,媒体和模板。所有站点都共享相同的用户群,实现了一种透明的单点登录/单点登录机制。它就像一个大型网站,跨越多个领域。

问题是,我的模板中有很多{% url %}个标签,当模板在其他网站上使用时,它们不起作用。我希望尽可能避免硬编码网址。

例如,在网站A(a.example.org)上我有一个

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

在A的URLconf中输入。然后,在某些global_menu.html模板中,我有{% url list_users %},显然效果很好,导致“/users/”。

现在,有站点B(b.example.org),与A共享许多内部组件。为了具有共同的外观,我想在站点B上使用相同的global_menu.html并希望{{ 1}}输出“{% url list_users %}”。我能做到这一点的最佳方式是什么?

目前,我正在为每个网站使用单独的http://a.example.org/users/,但这违反了DRY原则,并不是很方便。而且,是的,我正在使用Django的global_menu.html框架,在contrib.sites中为每个网站定义了不同的SITE_ID,但实际上还没有在其他地方使用它。

更新:目前我正在考虑重新实现settings.py代码或猴子修补url,以调用原始代码,并在异常情况下执行其他查找“外国URI列表”。如果已经存在这样的事情 - 我会很高兴听到。

提前感谢您的回答!

4 个答案:

答案 0 :(得分: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

然后在settings.py中列出URLconf,如下所示:

ROOT_URLCONF = 'project.urls_a'

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

答案 1 :(得分:2)

是的,你需要制作自己的{% url %}标签,该标签使用它自己的反转方法。

例如,要专门针对site_a urlconf进行反转,那么您可以使用如下方法:

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)

答案 2 :(得分:1)

使用@drdaeman

中的相同设置反向覆盖Django 1.7.x.
# -*- 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

我将代码放在urls.py文件中以便在启动时执行

答案 3 :(得分:0)

我建议做两处修改。 (1)如果您还没有将模板移动到公共目录(而不是每个应用程序)。 (2)调查新添加的URL namespaces功能。

第一个更改将允许您拥有一个公共基本模板,并有选择地为各种应用/网站覆盖它。第二个可能会使您的网址“更干燥”。