Django应用程序解析到错误的命名空间

时间:2016-08-22 13:49:27

标签: python django

在我的项目中,我有三个应用程序,“abc”,“xyz”和“common”。 Common并不是真正的应用程序,因为它只存储由两个应用程序继承和扩展的模板,模型和视图。

项目级别的urls.py看起来像这样,并正确地将请求重定向到相应的应用程序:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^abc/', include('abc.urls')),
    url(r'^xyz/', include('xyz.urls')),
]

两个应用程序的url.py文件都是这样的;唯一的区别是用XYZ替换每个ABC实例:

from django.conf.urls import url
from views import ABCAlertList as AlertList
from views import ABCEventList as EventList
from views import ABCEventDetail as EventDetail
from views import ABCEventReplay as EventReplay
from views import ABCUploadView as UploadView

urlpatterns = [
   url(r'^$', AlertList.as_view(), name='view_alerts'),
   url(r'^entities/(?P<uid>\w+)/$', EventList.as_view(), name='view_uid'),
   url(r'^entities/(?P<uid>\w+)/replay/$', EventReplay.as_view(), name='view_replay'),
   url(r'^entities/(?P<uid>\w+)/event/(?P<eid>\w+)/$', EventDetail.as_view(), name='view_event'),

   url(r'^upload/$', UploadView.as_view(), name='upload_file'),
]

同样,所有视图在两个应用之间都很常见,因此没有任何应用专用于其中任何一个。两个应用程序都在同一个通用模板中使用相同的行:

<a href="{% url 'view_uid' alert.uid %}">

现在,问题是:

App ABC在顶级页面上运行正常。但它渲染的网址经过那个点指向错误的应用程序。

例如,我将在

http://localhost:8888/abc/ 

并且该页面上的网址呈现为

http://localhost:8888/xyz/entities/262b3bce18e71c5459a41e1e6d52a946ab47e88f/

是什么给出的?看起来Django正在阅读错误的应用程序的urls.py。

1 个答案:

答案 0 :(得分:6)

Django只能通过视图名称和参数来说明abc/xyz/下的网址之间的区别。由于反转将以相反的顺序遍历模式,因此xyz/下的模式将始终匹配,因此使用reverse(){% url %}标记生成的所有链接都将指向{{1} } app。

您需要为每个模式指定唯一名称,或使用URL命名空间。在Django 1.9+中,您应该设置xyz属性:

app_name

在Django 1.8中,您需要将app_name = 'abc' urlpatterns = [ url(r'^$', AlertList.as_view(), name='view_alerts'), url(r'^entities/(?P<uid>\w+)/$', EventList.as_view(), name='view_uid'), url(r'^entities/(?P<uid>\w+)/replay/$', EventReplay.as_view(), name='view_replay'), url(r'^entities/(?P<uid>\w+)/event/(?P<eid>\w+)/$', EventDetail.as_view(), name='view_event'), url(r'^upload/$', UploadView.as_view(), name='upload_file'), ] 参数传递给namespace

include()

然后,您可以通过传递正确的命名空间来反转网址:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^abc/', include('abc.urls', namespace='abc')),
    url(r'^xyz/', include('xyz.urls', namespace='xyz')),
]

如果您需要为两个应用程序使用相同的模板或函数,则需要将两个应用程序的应用程序命名空间设置为相同,但使用不同的实例命名空间。

在1.9+中,这意味着使用相同的<a href="{% url 'abc:view_uid' alert.uid %}"> 属性,但传递不同的app_name参数:

namespace

在模板中,您需要使用应用程序命名空间来反转网址。将自动考虑当前实例名称空间。在调用# myapp/urls.py app_name = 'common_app_name' urlpatterns = [ # app urls ] # myproject/urls.py urlpatterns = [ url(r'^abc/', include('abc.urls', namespace='abc')), url(r'^xyz/', include('xyz.urls', namespace='xyz')), ] 时,您需要传递当前命名空间:

reverse()

在Django 1.8中,您没有reverse('common_app_name:view_alerts', current_app=request.resolver_match.namespace) 属性,需要将其作为参数传递给app_name

include()

Django 1.8还不会在调用urlpatterns = [ url(r'^abc/', include('abc.urls', namespace='abc', app_name='common_app_name')), url(r'^xyz/', include('xyz.urls', namespace='xyz', app_name='common_app_name')), ] 标记时自动使用当前实例名称空间。您需要为其设置{% url %}属性:

request.current_app