Django基础之路由层
路由的作用
路由即请求地址与视图函数的映射关系,在Django中路由默认配置在urls.py中,如下图:
路由配置的格式
# urls.py
from django.conf.urls import url
from django.contrib import admin
# 由一条条映射关系组成的urlpatterns这个列表称之为路由表
urlpatterns = [
url(r'^admin/', admin.site.urls), # Django自带的后台管理系统的路由匹配关系
url(regex, view, kwargs=None, name=None),
]
# url参数介绍:
# 1、regex:正则表达式,专门用来匹配url地址(url地址中所有内容均被当作字符串)的路径部分,不考虑请求方法如GET、POST或者域名,例如:
# 请求url地址为:https://www.example.com/myapp/,,正则表达式要匹配的部分是myapp/
# 请求url地址为: https://www.example.com/myapp/?page=3, 正则表达式要匹配的部分是myapp/
# 注意:
# 1.1 django的url配置不会考虑请求方法,换句话说,对于相同的URL地址,所有的请求方法如POST、GET、HEAD等,都将被路由到相同的功能view上
# 1.2 切记正则表达式开头无需加/
# 2、view:通常为一个视图函数,写函数的内存地址用来处理业务逻辑
# 3、kwargs:额外传递给视图函数的参数,可选(用法详见:分组)
# 4、name:为正则表达式匹配到的url地址起别名,可选(用法详见:反向解析
注意事项
注意一:
正则表达式不需要添加一个前导的反斜杠,因为每个URL都有。例如,应该是^index而不是 ^/index。
注意二:
每个正则表达式前面的'r' 是可选的但是建议加上。
注意三:
如果我们想匹配的路径就只是index/,那么正则表达式应该有开始符与结束符, 如 ^index/$。这样逻辑才算严谨
注意四:
刚刚我们在浏览器输入:http://127.0.0.1:8001/index/ ,Django会拿着路径部分index/去路由表中自上而下匹配正则表达式,一旦匹配成功,则立即执行其后的视图函数,不会继续往下匹配,此处匹配成功的正则表达式是 r'^index/$'。
注意五:
但是我们在浏览器输入:http://127.0.0.1:8001/index Django同样会拿着路径部分index去路由表中自上而下匹配正则表达式,貌似并不会匹配成功任何正则表达式( r'^index/$'匹配的是必须以 / 结尾,所以不会匹配成功index),但实际上仍然会看到结果 index page...,原因如下:
在配置文件settings.py中有一个参数APPEND_SLASH,该参数有两个值True或False。
默认是True,此时,Django会自动拿着路径部分(即index)去路由表中匹配正则表达式,发现匹配不成功,那么Django会在路径后加 / (即index/)再去路由表中匹配,如果匹配失败则会返回路径未找到,如果匹配成功,则会返回重定向信息给浏览器,要求浏览器重新向 http://127.0.0.1:8001/index/ 地址发送请求。
APPEND_SLASH = False
当APPEND_SLASH=False时,则不会执行上述过程,即一旦url地址的路径部分匹配失败就立即返回路径未找到,不会做任何的附加操作。
正则表达式
1.url函数第一个参数只写test
url(r'test', views.test),
验证:
http://127.0.0.1:8000/test/ 可以连接
http://127.0.0.1:8000/testadd/ 可以连接
http://127.0.0.1:8000/testaddghiaohahihio/ 可以连接
http://127.0.0.1:8000/gjieohaionaknatestaddghiahiio/ 可以连接
# 只要网址中存在test就能够连接服务端
2.^test/
url(r'^test/', views.test),
验证:
http://127.0.0.1:8000/test/ 可以连接
http://127.0.0.1:8000/testadd/ 不能
http://127.0.0.1:8000/test/agion/fag 可以连接
http://127.0.0.1:8000/bsznnztest/ehp/fjiphuu 不能
http://127.0.0.1:8000/ahruiht/test/agia/toim/ 不能
# 只要以test/开头就能够连接服务端
3.^test/$
url(r'^test/$', views.test),
验证:
http://127.0.0.1:8000/test/ 可以连接
http://127.0.0.1:8000/test/agia/toim/ 不能
http://127.0.0.1:8000/hta/test/agia/toim/ 不能
# ^以什么开头,$以什么结尾。所以只有test/才可以连接服务器
首页的路由:
url(r'^$', views.home),
分组
无名分组
无名分组:把一个正则表达式用小括号括起来。
单个分组:
url(r'^test/(\d+)/$', views.test),
多个分组:
url(r'^test/(\d+)/(\d+)/(\d+)/$', views.test),
无名分组就是把匹配的内容当成位置参数传递给视图函数,有几个分组,视图函数中就需要几个形参(形参可以任意取名)来接收。或者直接使用*args来接收(元组形式)。
路由传参数的方式:
1.问号传值
2.无名分组传值
具体使用:
def test(request, *args):
print(args)
return HttpResponse('test page')
# > ('257',)
# > ('333', '555', '666')
有名分组
有名分组:把一个正则表达式用小括号括起来,然后给这个括起来的内容起个名字
单个分组:
url(r'^testadd/(?P<year>\d+)/$', views.testadd),
多个分组:
url(r'^testadd/(?P<year>\d+)/(?P<month>\d+)/(?P<day>\d+)/$', views.testadd),
有名分组就是把匹配的内容当成key=value关键字参数传递给视图函数,有几个分组,视图函数就用几个形参来接收,并且形参名必须与有名分组中的名字一致。也可以使用**kwargs来接收,字典形式,可以用字典的键来取值。
具体使用:
def testadd(request, year, month, day):
print(year, month, day) # 2023 05 13
return HttpResponse('testadd page')
def testadd(request, **kwargs):
print(kwargs) # {'year': '2023', 'month': '05', 'day': '13'}
print(kwargs['year']) # 2023
return HttpResponse('testadd page')
'''无名和有名不要混合使用,但是,单个无名或者单个的有名可以多次使用'''
总结
无名分组和有名分组都是为了获取路径中的参数,并传递给视图函数,区别在于无名分组是以位置参数的形式传递,有名分组是以关键字参数的形式传递。
反向解析
可以给每一个路由起一个别名,然后,通过一些方法反向解析这个路由名字,可以得到这个路由对应的地址。是在一个函数中反向解析出另外一个路由名称。
关键函数:
Django提供了一个reverse()函数来实现反向解析。该函数接受视图函数的名称和可选参数作为参数,并返回关联的URL字符串。reverse()函数会返回一个字符串,我们可以将其传递给HttpResponseRedirect()函数,达到重定向的效果。需要注意的是,args参数必须以列表或元组的形式传递,即使只有一个参数。
使用场景:
使用reverse()函数可以避免在代码中硬编码URL字符串,方便维护和修改。
案例
urls.py
url(r'^index/$', views.index, name='xxx'), # 此时就可以动态修改路由url函数中的第一个参数的值,写的是什么,就可以反向解析出什么
后端反向解析
from django.shortcuts import reverse
print(reverse('xxx')) # /index/ /index/a/
前端反向解析
<a href="{% url 'xxx' %}">qqqqq</a>
无名分组反向解析
1.单个无名分组的使用:
urls.py
url(r'^index/(\d+)/', views.index, name='xxx')
后端的反向解析
print(reverse('xxx', args=(111,))) # /index/111/
# 需要指定一个参数,这个参数必须符合正则表达式
前端的反向解析
<a href="{% url 'xxx' 222 %}">qqqqq</a>
2.多个无名分组的使用:
urls.py
url(r'^index/(\d+)/(\w+)/$', views.index, name='xxx'),
后端的反向解析
print(reverse('xxx', args=(111, 'sss'))) # /index/111/sss/
# 多个参数都是写在arg元组中
前端的反向解析
<a href="{% url 'xxx' 555 'kkk' %}">qqqqq</a> # 多个参数用空格隔开
对于前端的反向解析,中间的参数一般会写什么?一般情况下都写的是主键id,可以在前端模板语法,for循环中使用。例如:
<a href="{% url 'yyy' foo.id %}">修改</a>
有名分组反向解析
1.单个有名分组的使用:
urls.py
url(r'^index/(?P<year>\d+)/', views.index, name='youming')
后端的反向解析
print(reverse('youming', kwargs={'year': 2023})) # /index/2023/
前端的反向解析
<a href="{% url 'youming' year=2023 %}">qqqqq</a>
2.多个有名分组的使用:
urls.py
url(r'^index/(?P<year>\d+)/(?P<kk>\w+)/', views.index, name='youming'),
后端的反向解析
print(reverse('youming', kwargs={'year': 2023, 'kk': 'nian'})) # /index/2023/nian/
前端的反向解析
<a href="{% url 'youming' year=2023 kk='nian' %}">qqqqq</a>
路由分发
随着项目功能的增加,app会越来越多,路由也越来越多,每个app都会有属于自己的路由,如果再将所有的路由都放到一张路由表中,会导致结构不清晰,不便于管理,所以我们应该将app自己的路由交由自己管理,然后在总路由表中做分发。路由分发是做应用的整合。
项目中的urls.py,叫总路由。每一个应用自己的路由文件称为,子路由。在应用里面默认是没有urls.py的,需要手动创建一个。
总路由分发的两种方式:
第一种方式
from app01 import urls as app01_urls # 起别名
from app02 import urls as app02_urls
urlpatterns = [
# app01/reg/
url(r'^app01/', include(app01_urls)),
# app02/reg/
url(r'^app02/', include(app02_urls)),
]
第二种方式
# app01/reg/
url(r'^app01/', include('app01.urls')),
# app02/reg/
url(r'^app02/', include('app02.urls')),
路由分发后,总路由就不用动了,以后就直接修改子路由。总路由中的后缀坚决不能加 $。
子路由:
# app01的urls.py
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^reg/$', views.reg)
]
# app02的urls.py
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'^reg/$', views.reg)
]
伪静态的概念
1.静态文件:文件中的内容是固定的。
2.伪静态:是把一些动态的网页伪装成静态网页。
3.为什么要伪装呢?
其实是因为静态的网页更加容易被搜索引擎抓取到。
4.怎么伪装?
在后缀上加.html。
url(r'^index.html/', views.index),
虚拟环境
一个虚拟环境相当于是一个纯净的python解释器!!!针对一个新的项目,解释器上只装跟本项目有关的模块,其余没用的都不装。
创建虚拟环境:
1.pycharm创建
使用虚拟环境:
2.命令行创建
python3.6以前的版本需要先下载一个模块。
命令行的方式:
python(解释器) -m venv 虚拟环境名字
示例:
python -m venv py38venv
注意:python命令此处不支持多版本共存的操作 python27 python36 python38这种不支持,想要给哪个解释器创建虚拟环境,需要把这个解释器在环境变量中的位置移动到上面。
需要激活虚拟环境:
先进到虚拟环境中:
cd py38venv
cd Scripts
激活
activate
关闭
deactivate
cmd终端中,如果左侧有有个括号,括号内是你建立的虚拟环境名称。就表示你已经进入到虚拟环境中了。
命令行创建虚拟环境也可以直接百度。一个博客
django2
1. django2中路由使用的是path
-
django1中路由使用的是url
-
django2中路由使用的是path
url支持的是正则,path不支持正则,path是精准匹配(写什么就匹配什么)
2.django2也可以使用正则
from django.urls import path, re_path
re_path就相当于django1中的url----------->支持正则
3.path支持5种转换器
转换器,是将对应位置匹配到的数据转换成固定的数据类型。Django2中默认支持以下5中转换器:
-
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
-
int,匹配正整数,包含0。
-
slug,匹配字母、数字以及横杠、下划线组成的字符串。
-
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
-
path,匹配任何非空字符串,包含了路径分隔符(/)
-
还支持自定义转换器(自己写正则表达式匹配更加细化的内容)
具体使用:
path('index/<str:info>/', views.index), # index(实参request对象,info='转换器匹配到的类型转换之后的内容')
path('index/<str:xxx>/<int:id>/', views.index_func) # index_func(实参request对象,xxx='转换器匹配到的类型转换之后的内容',id='转换器匹配到的类型转换之后的内容')
'''转换器<>匹配到的类型是关键字传参,传给对应的视图函数,所以视图函数要接收'''
4. 创建表关系
-
django1中的表关系是级联更新级联删除
-
django2需要执行on_delete参数