通常,我们会在每个app里,各自创建一个urls.py路由模块,然后从根路由出发,将app所属的url请求,全部转发到相应的urls.py模块中。
例如,下面是Django网站本身的URLconf节选。 它包含许多其它URLconf:
from django.urls import include, path urlpatterns = [ # ... 省略... path('community/', include('aggregator.urls')), path('contact/', include('contact.urls')), # ... 省略 ... ]
路由转发使用的是include()
方法,需要提前导入。它的参数是转发目的地路径的字符串,路径以圆点分割。
每当Django 遇到include()
时,它会去掉URL中匹配的部分并将剩下的字符串发送给include的URLconf做进一步处理,也就是转发到二级路由去。
另外一种转发其它URLconf的方式是使用一个path()实例的列表。 例如,下面的URLconf:
from django.urls import include, path from apps.main import views as main_views from credit import views as credit_views extra_patterns = [ path("reports/", credit_views.report), path("reports/<int:id>/", credit_views.report), path("charge/", credit_views.charge), ] urlpatterns = [ path("", main_views.homepage), path("help/", include("apps.help.urls")), path("credit/", include(extra_patterns)), ]
在此示例中,credit/reports/
URL将由credit_views.report()
视图处理。这种做法,相当于把二级路由模块内的代码写到根路由模块里一起了。
再看下面的URLconf:
from django.urls import path from . import views urlpatterns = [ path('<page_slug>-<page_id>/history/', views.history), path('<page_slug>-<page_id>/edit/', views.edit), path('<page_slug>-<page_id>/discuss/', views.discuss), path('<page_slug>-<page_id>/permissions/', views.permissions), ]
上面的路由可以改进,只需要声明共同的路径前缀一次,并将后面的部分分组转发:
from django.urls import include, path from . import views urlpatterns = [ path( "<page_slug>-<page_id>/", include( [ path("history/", views.history), path("edit/", views.edit), path("discuss/", views.discuss), path("permissions/", views.permissions), ] ), ), ]
这样就优雅多了,也清爽多了,但前提是你要理解这种做法。绝大多数情况下,我们推荐第一种做法。
目的地URLconf会收到来自父URLconf捕获的所有参数,看下面的例子:
# In settings/urls/main.py from django.urls import include, path urlpatterns = [ path('<username>/blog/', include('foo.urls.blog')), ] # In foo/urls/blog.py from django.urls import path from . import views urlpatterns = [ path('', views.blog.index), path('archive/', views.blog.archive), ]
在上面的例子中,捕获的"username"变量将被传递给include()指向的URLconf,再进一步传递给对应的视图。
path可以传递一个Python字典作为额外的关键字参数给视图函数,像下面这样:
from django.urls import path from . import views urlpatterns = [ path("blog/<int:year>/", views.year_archive, {"foo": "bar"}), ]
在上面的例子中,对于/blog/2005/
请求,Django将调用views.year_archive(request, year='2005', foo='bar')
。
理论上,你可以在这个字典里传递任何你想要的传递的东西。
但是要注意,URL模式捕获的关键字参数和在字典中传递的额外参数有如果具有相同的名字,会发生冲突,将使用字典里的参数来替代捕捉的参数。
类似上面,也可以传递额外的参数给include()。参数会传递给include指向的urlconf中的每一行。
例如,下面两种URLconf配置方式在功能上完全相同:
配置一:
# main.py from django.urls import include, path urlpatterns = [ path('blog/', include('inner'), {'blog_id': 3}), ] # inner.py from django.urls import path from mysite import views urlpatterns = [ path('archive/', views.archive), path('about/', views.about), ]
配置二:
# main.py from django.urls import include, path from mysite import views urlpatterns = [ path('blog/', include('inner')), ] # inner.py from django.urls import path urlpatterns = [ path('archive/', views.archive, {'blog_id': 3}), path('about/', views.about, {'blog_id': 3}), ]
小心了,这种情况下,二级路由的每个视图都应该注册了这个参数,否则会发生参数数量超出的问题。
路由转发能从一个APP转到另一个APP吗?比如我自己新建了一个question的APP,在login APP后,登录后,我想转到question中去怎么实现呢
直接url跳转
urlconf只有一级的匹配, 细化分发到view的参数,由查询字符串获得(request.GET.get(xx) / request.POST.get(xx) ), 配置更灵活,而且保护了网站的逻辑结构. 刘大大,怎么看呢?
老师 这个怎么理解啊?
在本节的例子中,它本身的含义并不重要。重要的是通过include将类似额一组url打包在了一起。