在学习urls映射之前,我们缕一缕Django打开网站的整个的执行流程,前一节很模糊的带过了,这里系统的说一下。
在终端执行
manage.py runserver的后,整个web项目就跑起来了,django会监听8000端口。访问127.0.0.1:8000的时候,django收到请求,然后通过urls(路由)指定的路径执行中的views.py中的方法(就算不是views.py其他名称的py文件也可以。)
项目一般顺序为:端口监听获取地址栏的路由信息->项目urls->app中的urls->views->templates中的html
整个Django可以看成一个app(只是多了一个manage.py文件),可以在项目中创建多个app已达到模块划分的目的。而app因为里面有__init__.py文件,所以也可以看成python中的模块的概念。
- include函数
- path函数
- 普通映射
- 传递参数
- 应用命名空间
- 实例命名空间
- include函数
- 自定义URL转换器
- URL反转
- re_path函数
include函数
一般地,include函数主要是用来包含其他app级的urls.py中的文件。然后通过path引用。
在项目的urls.py中通常这样写:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("helloworld.urls")),
path('', include("path1.path2.helloworld.urls")),
]
默认的,
urlpatterns是一个固定的变量名,django会通过这个名字来找路由。path方法中的include方法是让项目级的urls找到其他app级的url.py文件。
它怎么找得到我的app放在那里的呢?django默认是从项目根路径找的。
当然,我们也可以像
path('admin/', admin.site.urls)一样,导入这个app(本质上是一个python模块嘛),然后再找到urls
path函数
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("helloworld.urls")),
path('book/<int:book_id>',views.book,name='book',{'bookman':'huixiong'})
]
如上:
path('book/<int:book_id>',views.book,name='book',{'bookman':'huixiong'})是path方法的完整参数形式。(path是django2.0之后的函数,在之前并不是这样使用。)
- 参数①表示浏览器输入的路由
- 参数②表示是views中的方法def book()
- 参数③表示
name解耦合,方便访问 - 参数④表示传递额外的参数作为关键字到views
参数①
<int:book_id>表示要传递的参数以及参数的类型。
例如,我们在浏览器端访问的是127.0.0.1:8000/helloworld/book/123那么,django找路由的时候,就会匹配到这个路由,并访问views中的book方法,而book方法是可以获取到这个参数123的。
def book(request,book_id):
print(book_id)
return render(request,"helloworld.html")
参数②
一般为views.py中的方法,在urls.py开头需要from . import views
参数③
name可以理解为这里路由的名称,在项目大的时候使用方便,后面会讲到如何使用。
参数④
一旦该url被调用,那么就会讲参数④中的{bookman:huixiong}作为关键字:bookman=huixiong传递给view
普通映射
path('',views.hello)
传递参数
通过<>包含参数,可以限定其类型,只有符合类型才能匹配该路由。
- str:默认,非空。不能包含斜杠。
- int:匹配任意整型。
- slug:包含
-,_,英文字符,数字而成的字符串。 - uuid:匹配uuid字符串。
- path:匹配非空的英文字符串,可以包含斜杠。
# urls.py
path('getUrl/<who>',views.hello)
# views.py
def getUrl(request,who):
text = "获取的Url是: %s" % who
return HttpResponse(text)
通过GET传递参数
# urls.py
path('getGet/',views.getGet)
# views.py
def getGet(request):
name = request.GET.get("name")
text = "get传递的name是: %s" % name
return HttpResponse(text)
应用命名空间
# urls.py
app_name = 'book' # 这就是应用命名空间
path('login/',views.login,name='login')
# views.py
login_url = reverse('book:login') # 使其不会匹配到其他app中的name='login'的路由。
return redirect(login_url)
实例命名空间
由于一个app可以有多个实例。
# project中的urls
urlpatterns = [
path('app01/', include('apps.app01.urls')),
path('app02/', include('apps.app01.urls')),
]
而当我们访问localhost:8000/app02时,访问的默认是前面一个url的路径,浏览器地址栏的路径就会变成localohost:8000/app01。虽然这不一定会有什么影响。但是这两个路由指定的应该是不同的页面才对。所以添加实例命名空间如下:
# project 中的urls
urlpatterns = [
path('app01/', include('apps.app01.urls',namespace="app01")),
path('app02/', include('apps.app01.urls',namespace="app02")),
]
在views.py中获取实例命名空间来做跳转:
# 获取当前实例的命名空间
current_namespace = request.resolver_match.namespace
return redirect(reverse('%s:login' % current_namespace))
注意:使用实例命名空间之前必须给app设置应用命名空间。原理我也不是很清楚~
自定义URL转换器
自定义传递到
view中的参数类型。就是<int:book_id>中int等的扩展,其实能匹配更多的类型。 不常用,参考另一篇文章:点击这里
URL反转
# 在view中中使用该返回值,就会跳转指定路由,再由路由跳转view。
return redirect('/login/')
关于
url中name参数:讲到这里就可以知道name的用法了。 如下,代码所示:无论signin/如何修改都能找到真实路由。
# urls中:
path('signin/',views.login,name= 'login')
# 或
path('login/',views.login,name= 'login')
🤣
# views中:
login_url = reverse('login')
return redirect(login_url)
re_path函数
使用正则表达式捕获参数的时候,是用一个圆括号进行包裹,然后这个参数的名字是通过尖括号进行包裹,之后才是写正则表达式的语法。
from django.urls import path, re_path
from . import views
urlpatterns = [
path('articles/2003/', views.special_case_2003),
re_path(r'articles/(?P<year>[0-9]{4})/', views.year_archive),
re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.month_archive),
re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-_]+)/', views.article_detail),
]