05 路由层 分组 反向解析 路由分发 名称空间 2.0和1.0差别

django请求的生命周期

 一、路由层

(django2.0中路由层使用的是path,不是url,见手撸御姐系列)

 urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'', views.home),  #这样写完蛋了,你输入什么都走这个了,其他接口永远别想走
    url(r'^$', views.home),  #这样才是主页,127.0.0.1:8000会跳到这里
    url(r'test/', views.test), #这样写只要字符串中有test四个字都会跳到这里,如xxxtest,testadd
    url(r'^test/', views.test), #只要test/开头都会跳到这里,如test/xxxooo
    url(r'^test/$', views.test), #这样就只能是test/才能访问
    url(r'^testadd/', admin.testadd), #testadd也可以访问这里,从上至下匹配不到,系统会自动加上/再来找一次(前提是没有被上面的test半路抢劫)
1. url()方法 第一个参数 其实是一个正则表达式,请求来了会从上往下进行匹配,一旦前面的正则匹配到了内容 就不会再往下继续匹配 而是直接执行对应的视图函数

2. 正是由于上面的特性 当你的项目特别庞大的时候 url的前后顺序也是你需要你考虑,极有可能会出现url错乱的情况,后面的被前面的半路抢劫

3.django在路由的匹配的时候如果浏览器中没有敲最后的斜杠,django会先拿着你没有敲斜杠的结果去从上往下匹配,
   如果都没有匹配上,会自动在末尾加斜杠再发一次请求 再匹配一次,匹配上了就调用视图函数,如果还匹配不上才会报错     如果你想取消该机制,不想二次匹配可以在settings配置文件中 指定:                                  APPEND_SLASH
= False # 该参数默认是True,通常不这样干,都想省事嘛

二、有名分组和无名分组、反向解析

1.参数传递

1.无名分组
    url(r'^test/([0-9]{4})/', views.test)
    路由匹配的时候 会将括号内正则表达式匹配到的内容 当做位置参数传递给视图函数,即视图函数除了接收request参数外还要接收一个额外参数,名字随便
    例如:test(request,xxx)——> test(request,1234)

2.有名分组
    url(r'^test/(?P<year>\d+)/', views.test) #?P<名字>  是给正则\d+起名字叫year
    路由匹配的时候 会将括号内正则表达式匹配到的内容 当做关键字参数year=1234传递给视图函数,即视图函数除了接收request参数外还要接收一个额外关键字参数year
    test(request,year))——> test(request,1234)
3.不能混用
#
无名有名不能混合使用 !!! url(r'^test/(\d+)/(?P<year>\d+)/', views.test), 4.支持多个
虽然不能混用,但是用一种分组下 可以使用多个
# 无名分组支持多个
  url(r'^test/(\d+)/(\d+)/', views.test),
# 有名分组支持多个
  url(r'^test/(?P<year1>\d+)/(?P<year2>\d+)/', views.test),

2. 常规 反向解析

eg:56代码

假设你这个网站还未上线,经理心血来潮临时要求修改url,但是这个路径你已经在后端和前端都用了,而且成千上万个,基于这种情况如何修改?一个一个改?不如删库跑路吧!

其实很简单,我们可以使用反向解析,动态的获取到对应函数的路径

第一步:要给这个路由和视图函数对应关系起一个名字,后面直接用这个名字就可以了,具体做法如下:

url(r'^index/$',views.index,name='kkk')

第二步:根据前后端位置使用不同方法解析:

后端反向解析
    后端可以在任意位置通过reverse反向解析出对应的url
    from django.shortcuts import render,HttpResponse,redirect,reverse
    reverse('kkk')
    
前端反向解析<a href="{% url 'kkk' %}">111</a>
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', views.home),
    # 书籍展示页面
    url(r'^booklist/',views.book_list,name='list'), #name用于反向解析

    # 书籍新增
    url(r'^add_book/',views.add_book,name='add'),
    ]
urls.py
            <div class="list-group">
              <a href="#" class="list-group-item active">
                首页
              </a>
                <!-- /下面是路由反向解析 ++++++++++++++++++++++++++++++++++++++++++++++++ -->
              <a href="{% url 'list' %}" class="list-group-item">图书列表</a>
              <a href="#" class="list-group-item">出版社列表</a>
              <a href="#" class="list-group-item">作者列表</a>
              <a href="#" class="list-group-item">其他</a>
            </div>
html文件中反向解析

 

3.分组的反向解析

#无名分组

#无名分组反向解析
    url(r'^in/dex/(\d+)/$',views.index,name='kkk')
    
    后端:
        reverse('kkk',args=(1,))  # 后面的数字通常都是数据的id值
    前端:
        <a href="{% url 'kkk' 1 %}">按钮1</a>   # 后面的数字通常都是数据的id值

#有名分组(用法同无名分组)

#有名分组反向解析 
    url(r'^index/(?P<year>\d+)/$',views.index,name='kkk')
    
    后端:
        reverse('kkk',args=(1,)) # 推荐你使用上面这种  减少你的脑容量消耗
        reverse('kkk',kwargs={'year':1})
    前端:    
        <a href="{% url 'kkk' 1 %}">按钮1</a>  # 推荐你使用上面这种  减少你的脑容量消耗
        <a href="{% url 'kkk' year=1 %}">按钮2</a>

注意:在同一个应用下 别名千万不能重复!!!

#分组反向解析总结(统一格式)

总结:针对有名分组与无名分组的反向解析统一采用一种格式即可
后端
    reverse('kkk',args=(10,))  # 这里的数字通常都是数据的主键值
前端
    {% url 'kkk' 10 %}
反向解析的本质:本质上就是给url和视图函数对应关系起别名,然后通过别名获取到一个能够访问对应视图函数的具体URL地址

4.反向解析应用

我们想获取前端传过来的数据可以使用反向解析了

路由:
url(r'^edit/(\d+)/',views.edit,name='edit')
前端模板语法: {
%for user_obj in user_list%} <a href='edit/{{ user_obj.pk }}/'></a> {% endfor %} 视图函数 from django.shortcuts import reverse def edit(request,edit_id): url = reverse('edit',args=(edit_id,)) 模板 {% url 'edit' edit_id %}

三、路由分发

当你的django项目特别庞大的时候 路由与视图函数对应关系特别特别多
那么你的总路由urls.py代码太过冗长 不易维护

实现多人分组开发 :等多人开发完成之后 我们只需要创建一个空的django项目
然后将多人开发的app全部注册进来 在总路由实现一个路由分发,而不再做路由匹配(来了之后, 我只给你分发到对应的app中)

每一个应用都可以有自己的urls.py,static文件夹,templates文件夹(******)

django每一个app下面都可以有自己的urls.py路由层,templates文件夹,static文件夹。

  项目名下的/urls.py(总路由)不再做路由与视图函数的匹配关系,而是做路由的分发

具体做法:

#总urls中路由分发

from django.conf.urls import url,include

    from app01 import urls as app01_urls  #名字重复起别名
    from app02 import urls as app02_urls  
    url(r'^app01/',include(app01_urls))   #直接include(app01_urls) 就可以达到分发的效果
    url(r'^app02/',include(app02_urls))  #总路由中 一级路由的后面千万不加$符号      

#各app中urls

from django.conf.urls import url
from app01 import views
    urlpatterns = [
        url(r'^index/',views.index)
    ]

ps:同样的思想,当你的应用下的视图函数特别特别多的时候 你也可以建一个views文件夹, 里面根据功能的细分再建不同的py文件(******)

 四、名称空间

命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。

由于name没有作用域,Django在反向解析URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回
我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间
多个app起了相同的别名 这个时候用反向解析 并不会自动识别应用前缀
如果想避免这种问题的发生,总路由分发时指定名称空间,前、后端解析的时候声明名称空间
方式1:

    总路由
        url(r'^app01/',include('app01.urls',namespace='app01'))
        url(r'^app02/',include('app02.urls',namespace='app02'))

    后端解析
        reverse('app01:index')
        reverse('app02:index')
    前端解析
        {% url 'app01:index' %}
        {% url 'app02:index' %}

方式2:
    起别名的时候不要冲突即可  一般情况下在起别名的时候通常建议以应用名作为前缀
        name = 'app01_index'
        name = 'app02_index'

五、伪静态

静态网页:数据是写死的 万年不变

伪静态网页的设计是为了增加百度等搜索引擎seo查询力度

url(r'^index.html',views.index,name='app01_index')

所有的搜索引擎其实都是一个巨大的爬虫程序,发现.html结尾误以为是静态网页,就会优先展示

网站优化相关 通过伪静态确实可以提高你的网站被查询出来的概率,但是再怎么优化也抵不过RMB玩家

六、虚拟环境

平时我们的python中下载了很多模块,创建项目的时候会全部加载,累的一批,那么怎样只让python只保留我们当前项目需要的模块资源呢?慢慢删除不需要的模块?累哭你

可以创建虚拟环境,我们会给每一个项目 配备该项目所需要的模块 不需要的一概不装

虚拟环境 就类似于为每个项目量身定做的解释器环境


如何创建虚拟环境:
每创建一个虚拟环境 就类似于你又下载了一个全新的python解释器(所以虚拟环境不能一直创建,消耗的都是资源啊老哥)

 

 七、django版本区别

1.path差别

django1.X跟django2.X版本区别
    路由层1.X用的是url
    而2.X用的是path
    
    2.X中的path第一个参数不再是正则表达式,而是写什么就匹配什么 是精准匹配
    
    当你使用2.X不习惯的时候  2.X还有一个叫re_path
    2.x中的re_path就是你1.X的url
    
    
虽然2.X中path不支持正则表达式  但是它提供了五种默认的转换器

    1.0版本的url和2.0版本的re_path分组出来的数据都是字符串类型
    默认有五个转换器,感兴趣的自己可以去试一下
    str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
    int,匹配正整数,包含0。
    slug,匹配字母、数字以及横杠、下划线组成的字符串。
    uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
    path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)

 

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>/', views.article_detail),  
  # path才支持,re_path不支持
  path('order/<int:year>',views.order),
]  

基本规则:

  • 使用尖括号(<>)从url中捕获值。
  • 捕获值中可以包含一个转化器类型(converter type),比如使用 <int:name> 捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符。
  • 无需添加前导斜杠。

以下是根据 2.0官方文档 而整理的示例分析表:(跟上面url的匹配关系)

 

 

2.自定义转换器

对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:

  • regex 类属性,字符串类型
  • to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
  • to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用
class FourDigitYearConverter:  
    regex = '[0-9]{4}'  
    def to_python(self, value):  
        return int(value)  
    def to_url(self, value):  
        return '%04d' % value  

使用register_converter 将其注册到URL配置中:

from django.urls import register_converter, path  
from . import converters, views  
register_converter(converters.FourDigitYearConverter, 'yyyy')  
urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<yyyy:year>/', views.year_archive),  
    ...  
]  

 

 

posted @ 2019-09-22 21:59  www.pu  Views(339)  Comments(0Edit  收藏  举报