我一直在使用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_name
是myapp.urls
中包含的网址格式的名称。由于我使用名称空间,这将引发错误:没有名为view_name
的视图。相反,我必须告诉它instance1:view_name
或instance2:view_name
。但动态地这样做会让我感到难过。
我做了一些查看,看起来传递给current_app
或Context
的{{1}}参数,旨在帮助解决这个问题,但根本不清楚如何动态将右应用程序名称传递给RequestContext
。那么告诉Django使用哪个命名空间的正确方法是什么?
编辑:我的用例是多次使用应用程序的单个安装。也就是说,它只存在于磁盘上一次,但在项目的根current_app
中被多次包含(每次都在不同的命名空间下,如上例所示)。考虑到这一点,是否有任何好方法可以跟踪调用视图/模板的命名空间,并在同一命名空间中使用urls.py
或reverse()
?我知道Django 1.3将提供一些可以帮助解决这个问题的额外功能(即new and improved resolve()
),但是现在肯定有一个很好的方法可以做到这一点......
答案 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.path
(request.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