2. urls映射

470 阅读5分钟

在学习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中的模块的概念。

  1. include函数
  2. path函数
  3. 普通映射
  4. 传递参数
  5. 应用命名空间
  6. 实例命名空间
  7. include函数
  8. 自定义URL转换器
  9. URL反转
  10. 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/')

关于urlname参数:讲到这里就可以知道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),
]