路由层
url
定义
URL即统一资源定位符,网络资源的地址,包含对应文件的位置和浏览器对该资源的处理方式。
格式
schema://host[:port#]/path/.../[?query-string][#anchor] # 栗子:http://zdq.com/index/ **schema:**协议,如http,https,ftp等; **host:**地址或域名; **port:**端口号,http默认端口80; **path:**资源路径,用于匹配需要访问的资源; **query-string:**向服务器发送的数据参数; **anchor:**锚点。
urls.py
url加载是从配置文件rurls.py开始的,django项目中,urls.py文件是一张映射表,将项目中声明的url对应的视图函数建立映射关系.
网页向后端发送想要访问的接口,只有输入url的路径与配置文件中路径参数一致时,后端通过urls路由层来找到前端需求对应的接口.
路由匹配
settings中参数默认APPEND_SLASH = True,可手动设置为False
作用是django会自动给传到后端的url后加/
第一步,先用原url寻找,
第二步,如果找不到,url后加/
再寻找
第三步,如果害是找不到,404NotFound
匹配规则
url后第一个参数是正则表达式,将前端传来的url当作字符串进行匹配,如匹配成功,立刻返回,
所以建议再url中的函数名后加/
urlpatterns = [ url(r'^admin/', admin.site.urls), # url第一个参数是一个正则表达式 url(r'^test/$', views.test), # 一旦正则表达式能够匹配到内容 会立刻结束匹配关系 直接执行后面对应的函数 url(r'^testadd/$', views.testadd),#^标识开头,$标识结尾 ] # django匹配路由的规律 # 不加斜杠 先匹配一次试试 如果匹配不上 会让浏览器重定向 加一个斜杠再来一次 如果还匹配不上 才会报错
注意:
路由匹配值匹配url部分
不匹配?后面的get携带的参数
无名分组
将分组内正则表达式匹配到的内容当作==位置参数==传递给视图函数.
url(r'^wuminggroup/([0-9]{4})/([0-9]{4})/', views.wuminggroup), -------------------------------- def wuminggroup(request,*args): for i in args: print(i) # print(args) return HttpResponse('200 ok')
有名分组
会将分组内的正则表达式匹配到的内容当作==关键字参数==传递给视图函数
url(r'^youminggroup/(?P<kwargs>\d+/)', views.youminggroup), -------------------------------- def youminggroup(request,kwargs): print(kwargs) return HttpResponse("kwargs")
利用有名和无名分组,我们就可可以再调用视图函数之前给函数传递额外的参数.
注意:
无名和有名分组不能同时使用,
但是同一种分组的情况下,同一种类可以使用多次(无名* n 或者 有名 * n)
无名可以使用
*args
接收,有名必须给定key值.
反向解析
根据一个别名,动态解析出一个结果,该结果可以直接访问对应的url
情况1:路由中没有正则
写死的
#urls.py url(r'^home/', views.home,name='xxx'), # 给路由与视图函数对应关系起别名
前端反向解析
#html <p><a href="{% url "xxx"%}">111</a></p>
后端反向解析
#views from django.shortcuts import render,HttpResponse,redirect,reverse def get_url(request): url = reverse('xxx') print(url) return HttpResponse("get_url")
情况二:无名分组的反向解析
在解析时,需要手动指定正则匹配的内容
#urls.py url(r'^home/(\d+)/', views.home,name='xxx'), # 给路由与视图函数对应关系起别名
前端反向解析
#html <p><a href="{% url "xxx" user_obj.id %}">111</a></p>
后端反向解析
#views def get_url(request): url = reverse('xxx',args=(1,)) print(url) return HttpResponse('get_url')
手动传入参数,需要满足能够被正则表达式匹配的到.
情况三:有名分组反向解析
在解析时,需要手动指定正则匹配的内容
有名分组的反向解析可以与无名分组的一样
但是,最最正规的写法:
url(r'^home/(?P<year>\d+)/', views.home,name='xxx'),
# 给路由与视图函数对应关系起别名
前端反向解析
# 可以直接用无名分组的情况 <p><a href="{% url 'xxx' 12 %}">111</a></p> # 你也可以规范写法 <p><a href="{% url 'xxx' year=1232 %}">111</a></p> # 了解即可
后端反向解析
# 可以直接用无名分组的情况 url = reverse('xxx',args=(1,)) # 你也可以规范写法 url = reverse('xxx',kwargs={'year':213123}) # 了解即可
小例子:
url(r'^edit_user/(\d+)/',views.edit_user,name='edit') def edit_user(request,edit_id): # edit_id就是用户想要编辑数据主键值 pass {% for user_obj in user_list %} <a href='/edit_user/{{user_obj.id}}/'>编辑</a> 无名分组 <a href='{% url 'edit' user_obj.id %}'>编辑</a> 反向解析 {% endfor %}
PS:这个后端反向解析,除了集体改名方便,也不知道还有啥用
路由分发
为了使多个app同时开发互相不干扰,
路由分发就是为了解决项目的总路由匹配关系过多的情况
每个app下手动创建urls.py存放自己的路由
app01下的urls.py
from django.conf.urls import url # 导入app01的views from app01 import views urlpatterns = [ url(r'^index/$',views.index), ]
app01下的views.py
from django.shortcuts import render from django.shortcuts import HttpResponse def index(request): return HttpResponse('我是app01的index页面...')
app02下的urls.py
from django.conf.urls import url # 导入app02的views from app02 import views urlpatterns = [ url(r'^index/$',views.index), ]
app02下的views.py
from django.shortcuts import render from django.shortcuts import HttpResponse def index(request): return HttpResponse('我是app02的index页面...')
总urls.py文件
from django.conf.urls import url,include from django.contrib import admin # 总路由表 urlpatterns = [ url(r'^admin/', admin.site.urls), # 新增两条路由,注意不能以$结尾 # include函数就是做分发操作的,当在浏览器输入http://127.0.0.1:8001/app01/index/时,会先进入到总路由表中进行匹配,正则表达式r'^app01/'会先匹配成功路径app01/,然后include功能会去app01下的urls.py中继续匹配剩余的路径部分 url(r'^app01/', include('app01.urls')), url(r'^app02/', include('app02.urls')), ]
测试:
python manage.py runserver 8000 # 在浏览器输入:http://127.0.0.1:8000/app01/index/ 会看到:我是app01的index页面... # 在浏览器输入:http://127.0.0.1:8000/app02/index/ 会看到:我是app02的index页面...
名称空间
当多个app同时存在,且每个app下都对匹配的路径起了别名,如果别名重复,在反向解析时i会出现覆盖
为了解决这个问题,如果像使用相同的别名,就需要将别名放到不同的名称空间中,这样即使重复也不会冲突,
在总路由urls.py分发时,指定名称空间
from django.conf.urls import url, include from django.contrib import admin # 总路由表 urlpatterns = [ url(r'^admin/', admin.site.urls), # 传给include功能一个元组,元组的第一个值是路由分发的地址,第二个值则是我们为名称空间起的名字 url(r'^app01/', include(('app01.urls','app01'))), url(r'^app02/', include(('app02.urls','app02'))), ]
修改每个app下的view.py中视图函数,针对不同名称空间中的别名'index_page'做反向解析
app01下的views.py
from django.shortcuts import render from django.shortcuts import HttpResponse from django.shortcuts import reverse def index(request): url=reverse('app01:index_page') # 解析的是名称空间app01下的别名'index_page' return HttpResponse('app01的index页面,反向解析结果为%s' %url)
app02下的views.py
from django.shortcuts import render from django.shortcuts import HttpResponse from django.shortcuts import reverse def index(request): url=reverse('app02:index_page') # 解析的是名称空间app02下的别名'index_page' return HttpResponse('app02的index页面,反向解析结果为%s' %url)
总结:
1、在视图函数中基于名称空间的反向解析,用法如下 url=reverse('名称空间的名字:待解析的别名') 2、在模版里基于名称空间的反向解析,用法如下 <a href="{% url '名称空间的名字:待解析的别名'%}">哈哈</a>
使用app名加url名作为别名,永不重复!
伪静态
在url最后加上.html
,将一个动态网页伪装成动态网页,以此来增加搜索引擎SEO查询频率和收藏力度
虚拟环境
相当于每创建一个虚拟环境就重新下载了一个纯净的python解释器
django版本区别
django1.X django2.X
urls.py中路由匹配的方法有区别 django2.X用的是path urlpatterns = [ path('admin/', admin.site.urls), ] django1.X用的是url urlpatterns = [ url(r'^reg.html',views.reg,name='app02_reg') ] # 区别 django2.X里面path第一个参数不是正则也不支持正则 写什么就匹配什么 # 虽然path不支持正则 感觉也好用 django2.X还有一个re_path的方法 该方法就是你django1.X里面url # 虽然path支持 但是它提供了五种转换器 能够将匹配到的数据自动转黄成对应的类型 # 除了有默认五种转换器之外 还支持你自定义转换器
1、path与re_path或者1.0中的url的不同之处是,传给path的第一个参数不再是正则表达式,而是一个完全匹配的路径,相同之处是第一个参数中的匹配字符均无需加前导斜杠
2、使用尖括号(<>)从url中捕获值,相当于有名分组
3、<>中可以包含一个转化器类型(converter type),比如使用 <int:name> 使用了转换器int。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符
五种默认的转换器
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式 int,匹配正整数,包含0。 slug,匹配字母、数字以及横杠、下划线组成的字符串。 uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。 path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)