【Django】Django 路由规则

Posted by 西维蜀黍 on 2019-11-10, Last Modified on 2021-09-21

编写urlpatterns

最简单的情况

#urls.py
    from app import views #这里的app是你自己的应用的名字
    from django.urls import path
    urlpatterns = [
                path('index/', views.index, name='index'),
    ]

该方法对应view.py中的函数为:

#views.py
def index(request):
    ...
    return render(request,'index.html')

从views中继承的类

#urls.py
from app.views import LoginView
from django.urls import path
urlpatterns = [
            path('login/', LoginView.as_view(), name='login'),
] 

该方法对应的view.py中为:

#views.py
class LoginView(View):
    # 请求为get时
    def get(self,request):
        ...
        return render(request, 'login.html')
    # 请求为post时
    def post(self,request):
        ...
        return render(request,'login.html')

使用include()

如果我们的 Django 项目比较大,可能会将每个模块都写在一个 Django App 中,这时候就需要用到 include() 以将其他 Django App 的路由规则引入到Django 项目中。

在Django 项目的 urls.py中:

urlpatterns = patterns(
	'',
	...

	(r'^user/',         include('backend.user.urls')),
	(r'^product/',      include('backend.product.urls'))
)

在 user 这个 Django App(位于 user 文件夹)的 urls.py 中,定义了这个App 中对应的路由规则。

urlpatterns = patterns(
	'',
	(r'^$', views.home),
	(r'^json/$', views.home_json),

	(r'^account_info/(?P<userid>\d+)/$', views.account_info),
	(r'^account_info/(?P<userid>\d+)/post/$', views.account_info_post),
	...
)

# views.py
def account_info(request, userid):
  ...

当用户访问 127.0.0.0/user/account_info/(?P<userid>\d+)/ 时,user 这个 Django App 下的 views.account_info 方法就会被调用以响应 request。

How Django processes a request

When a user requests a page from your Django-powered site, this is the algorithm the system follows to determine which Python code to execute:

  1. Django determines the root URLconf module to use. Ordinarily, this is the value of the ROOT_URLCONF setting, but if the incoming HttpRequest object has a urlconf attribute (set by middleware), its value will be used in place of the ROOT_URLCONF setting.

  2. Django loads that Python module and looks for the variable urlpatterns. This should be a sequence of django.urls.path() and/or django.urls.re_path() instances.

  3. Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL.

  4. Once one of the URL patterns matches, Django imports and calls the given view, which is a simple Python function (or a class-based view). The view gets passed the following arguments:

  • An instance of HttpRequest.
  • If the matched URL pattern returned no named groups, then the matches from the regular expression are provided as positional arguments.
    • The keyword arguments are made up of any named parts matched by the path expression, overridden by any arguments specified in the optional kwargs argument to django.urls.path() or django.urls.re_path().
  1. If no URL pattern matches, or if an exception is raised during any point in this process, Django invokes an appropriate error-handling view. See Error handling below.

$ 和 ^ 的含义

$

如果定义为:

urlpatterns = [
	url(r'a', views.a),
	url(r'a/b', views.b),
]

那么当访问 http://127.0.0.1:8001/a/b 时,会由 views.a 来处理(而不是 views.b)。因为路由匹配的原则是:从上至下开始匹配,一旦匹配到了某一条规则,则不再继续向下匹配。

若希望 http://127.0.0.1:8001/a/b 能够被路由到 views.b,则需要进行如下定义:

urlpatterns = [
	url(r'a/$', views.a),
	url(r'a/b$', views.b),
]

在正则表达式中,$表示匹配输入字符串的结尾位置,因此除 querystring 部分之外,URL 的结尾为 a/ 的都会被路由到 views.a,比如:

  • http://127.0.0.1:8001/a/
  • http://127.0.0.1:8001/sa/
  • http://127.0.0.1:8001/zzzzzza/
  • http://127.0.0.1:8001/a/?name=ss,name=ss 这个部分就是 querystring

^

你可能注意到了,http://127.0.0.1:8001/sa/也会被匹配到 views.a,这时候,你就需要 ^了,^ 表示匹配输入字符串的开始位置,即 IP和端口之后的字符串。

urlpatterns = [
	url(r'^a/$', views.a),
	url(r'^a/b$', views.b),
]

这样,有且仅有在端口之后、querysting 之前为 a/ 的 URL 才能被匹配到 views.a ,即http://127.0.0.1:8001/a/,而http://127.0.0.1:8001/sa/显然不能。

总结

我们推荐在所有路由规则中,均加上^和$,以帮助精确匹配。

一些正则

在Python 正则表达式中,命名正则表达式组的语法是(?P<name>pattern),其中name 是组的名称,pattern 是要匹配的模式。

Example

Here’s a sample URLconf:

from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

Notes:

  • To capture a value from the URL, use angle brackets.
  • Captured values can optionally include a converter type. For example, use <int:name> to capture an integer parameter. If a converter isn’t included, any string, excluding a / character, is matched.
  • There’s no need to add a leading slash, because every URL has that. For example, it’s articles, not /articles.

Example requests:

  • A request to /articles/2005/03/ would match the third entry in the list. Django would call the function views.month_archive(request, year=2005, month=3).
  • /articles/2003/ would match the first pattern in the list, not the second one, because the patterns are tested in order, and the first one is the first test to pass. Feel free to exploit the ordering to insert special cases like this. Here, Django would call the function views.special_case_2003(request)
  • /articles/2003 would not match any of these patterns, because each pattern requires that the URL end with a slash.
  • /articles/2003/03/building-a-django-site/ would match the final pattern. Django would call the function views.article_detail(request, year=2003, month=3, slug="building-a-django-site").

Reference