9

可能很简单的问题,我只是错过了一些东西,但我没有想法。

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

问题是,我的模板中有很多{% url %}标签,当模板在其他网站上使用时它们不起作用。而且我想尽可能避免对 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 共享许多内部结构。为了有共同的外观和感觉,我想global_menu.html在站点 B 上使用相同的并希望{% url list_users %}输出“ http://a.example.org/users/”。我能做到这一点的最佳方法是什么?

目前,我global_menu.html为每个站点使用单独的,但这违反了 DRY 原则,并且不是很方便。而且,是的,我正在使用 Django 的contrib.sites框架,并为每个站点SITE_ID定义了不同的 s settings.py,但实际上还没有在其他任何地方使用它。

更新:目前我正在考虑重新实现urltag 或 monkey-patching reverse(),调用原始的,并在异常情况下在一些“外部 URI 列表”中执行额外的查找。如果已经存在这样的东西——我很高兴听到。

预先感谢您的回答!

4

4 回答 4

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

然后像这样列出 URLconfs settings.py

ROOT_URLCONF = 'project.urls_a'

EXTERNAL_URLCONFS = (
    ('http://b.example.com/', 'project.urls_b'),
)
于 2009-08-04T23:21:30.177 回答
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)
于 2009-08-04T21:08:42.847 回答
2

使用来自@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 文件中以在启动时执行

于 2015-01-08T12:12:34.853 回答
0

我建议进行两个更改。(1) 如果您还没有将模板移动到公共目录(而不是每个应用程序)。(2) 研究新添加的 URL命名空间功能。

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

于 2009-08-03T16:53:42.573 回答