在Django中反转命名空间的URL:同一个应用程序的多个实例

时间:2010-11-20 01:09:46

标签: django namespaces

我一直在使用Django一段时间(目前在1.2版本上),但最近才开始研究需要支持多个实例的应用程序。例如,项目urls.py文件将在两个不同的名称空间下包含两次,如下所示:

urlpatterns = patterns('',
    (r'^instance1/', include('myapp.urls', namespace='instance1')),
    (r'^instance2/', include('myapp.urls', namespace='instance2')),
)

我一直很顺利,直到我意识到我需要弄清楚如何处理reverse()的所有内部调用(或{% url %}过滤器的模板调用)。例如,假设我在我的一个观点中做了类似下面的事情:

return HttpResponseRedirect(reverse('view_name'))
在我的一个模板中

或类似的东西:

<a href="{% url view_name %}">link text</a>

...其中view_namemyapp.urls中包含的网址格式的名称。由于我使用名称空间,这将引发错误:没有名为view_name的视图。相反,我必须告诉它instance1:view_nameinstance2:view_name。但动态地这样做会让我感到难过。

我做了一些查看,看起来传递给current_appContext的{​​{1}}参数,旨在帮助解决这个问题,但根本不清楚如何动态将应用程序名称传递给RequestContext。那么告诉Django使用哪个命名空间的正确方法是什么?

编辑:我的用例是多次使用应用程序的单个安装。也就是说,它只存在于磁盘上一次,但在项目的根current_app中被多次包含(每次都在不同的命名空间下,如上例所示)。考虑到这一点,是否有任何好方法可以跟踪调用视图/模板的命名空间,并在同一命名空间中使用urls.pyreverse()?我知道Django 1.3将提供一些可以帮助解决这个问题的额外功能(即new and improved resolve()),但是现在肯定有一个很好的方法可以做到这一点......

5 个答案:

答案 0 :(得分:4)

自问题发布以来已经发生了很多变化,但对于未来的googlers(像我一样),指出request现在具有命名空间可能是有用的(至少从1.7开始,如this example所示。

根据我的理解,我们应该能够简单地将current_app位置参数传递给reverse / redirect,但我无法让它工作,所以我最终创建了一个帮助方法为此目的:

def __redirect(request, viewname, *args, **kwargs):
    to = viewname

    if callable(to):
        to = viewname.__module__ + '.' + viewname.__name__
    if request.resolver_match.namespace:
        to = '%s:%s' % (request.resolver_match.namespace, to)

    return redirect(
        to,
        *args,
        **kwargs
    )

我在这里使用redirect,但所有参数都传递给reverse,所以它是一样的。

答案 1 :(得分:3)

不是一个非常好的解决方案,但由于您对命名空间和URL路径的初始部分使用相同的文本,因此可以从request.pathrequest.path.split('/')[1])中提取该元素并将其设置为{ {1}}在请求上下文中,或者仅将其用作视图中的命名空间。

http://docs.djangoproject.com/en/dev/topics/http/urls/#url-namespaces第2点。

你可以这样做,例如在上下文处理器中(如果要在模板中使用命名空间)。

对于视图,您可以编写一个装饰器,为您的函数提供额外的kwarg“命名空间”并将其用作:

current_app

或者只是用一个额外的param(请求)编写一个reverse_namespaced函数,其中函数从中获取命名空间,并使用它而不是反向。

当然,如果您这样做,您将始终必须为此应用程序使用请求路径/命名空间

答案 2 :(得分:2)

有关于撤消命名空间网址的文档页面。

http://docs.djangoproject.com/en/dev/topics/http/urls/#topics-http-reversing-url-namespaces

reverse('instance1:myapp.urls.some_view')reverse('instance1:view_name')应该有效,或两者都有效:) - 我自己从未尝试过。

答案 3 :(得分:2)

current_app变量是你必须自己设定的东西。

就我个人而言,我建议您将其设置为__name__.rsplit('.', 1)[0],以便在spam中获得spam/views.py

但您可以将其定义为您喜欢的任何内容,只要您的应用名称与您在网址文件中定义的内容一致即可。

答案 4 :(得分:1)

如果你没有过多地依赖名称空间,你可以改为将你的urls.py写成:

urlpatterns = patterns('',
    (r'^(P<instance>/)', 'controllers.route_me'),
)

这将调用controllers.route_me函数并将请求传递给它,加上字符串'instance',你可以这样处理:

# (in controllers.py)
def route_me(request, instance):
    # you now have complete control, and do what you need to do with the 'instance' and 'request' vars
    pass