django之路由层
一、django请求生命周期流程图
首先,用户在浏览器中输入url,发送一个GET或POST方法的request请求。
Django中封装了socket的WSGi服务器,监听端口接受这个request 请求,
再进行初步封装,然后传送到中间键中,这个request请求再依次经过中间键,
对请求进行校验或处理,再传输到路由系统中进行路由分发,匹配相对应的视图函数(FBV),
再将request请求传输到views中的这个视图函数中,进行业务逻辑的处理,
调用modles中表对象,通过orm拿到数据库(DB)的数据。
同时拿到templates中相应的模板进行渲染,然后将这个封装了模板response响应传输到中间键中,
依次进行处理,最后通过WSGi再进行封装处理,响应给浏览器展示给用户。

二、路由匹配
# path('网址后缀',函数名) 网址后缀一旦匹配上就会执行后面函数功能 并结束整个路由匹配 # 1.路由结尾的斜杠 默认情况下不写斜杠 django会做二次处理 第一次匹配不上 会让浏览器加斜杠再次请求 如果再匹配不上才会报错 django配置文件中可以指定是否自动添加斜杠 APPEND_SLASH = False 但是尽量不要加 因为加了用户输入的时候就必须加斜杠 体验会不好 # 2.path转换器 就是当我们写网址后缀的时候如果想要加上一些不固定的数字或字母的时候不好写匹配就有了转换器 'int': IntConverter(), 'path': PathConverter(), 'slug': SlugConverter(), 'str': StringConverter(), 'uuid': UUIDConverter(), path('func/<int:year>/<str:info>/', views.func) # 就是将func后面的后缀的输入字符装换成整型 再后面的后缀转换成浮点型 转换器匹配到的内容会当做视图函数的关键字参数传入 转换器有几个叫什么名字 那么视图函数的形参必须对应 def func(request,year,info): # year和info的值就是网址后面写的值 pass # 3.re_path匹配 from django.urls import path,re_path re_path匹配就跟django的路由是一样的了都是正则匹配 re_path(正则表达式,函数名) '''一旦网址后缀的正则能够匹配到内容就会自动执行后面的函数 并结束整个路由的匹配 所以只要能够匹配都会直接结束这个时候不过网址这么写只要能够匹配就可以执行 eg: 待匹配路由: re_path('test/', views.test), 网页发送的url: 127.0.0.1:8000/test/46545646 127.0.0.1:8000/hdsjtest/ahdjs 上述两种情况都能匹配上那么这样肯定是不对的 但是有是正则匹配所以我们只需这样写即可: re_path('^test/$', views.test) 这个时候就实惠匹配test在开头和/必须在test才可以匹配 ''' # 4.无名分组 '''就是当我们写网址后缀的时候如果想要加上一些不固定的数字或字母的时候re_path就需要正则来搞定就是无名分组''' re_path('^index/(\d+)/(.*?)/, views.index), '''这个时候网页index/后面写什么数字都能匹配上在后面的后缀写什么都可以 然后()中匹配到的内容会被当做位置参数传给后面函数 有几个传几个 形参也是有几个写几个''' def index(request, a, b): # a和b的值就是网页后面你写的内容 pass # 5.有名分组 re_path('^index/(?P<year>\d+)/(?P<others>.*?), views.index) '''这个时候index/后面的匹配的内容就会有了名字 因为这个是正则表达式给匹配的内容的起名方式 然后这个名字就会被当做关键字参数传入后面的函数有几个传几个 形参有几个写几个''' def index(request, year, others): # year和 others的值就是网页后面你写的内容 pass 6.django版本区别 '''在django1.11中 只支持正则匹配 并且方法是 url() django2,3,4中 path() re_path() 等价于 url()'''
三、反向解析
'''页面上写好了很多了路由 有时候如果路由的名称改变了 那么浏览器访问的页面就会访问不到 这个时候我们就需要去页面上修改名称 这样会很不方便 这个时候我们就可以使用反向解析解决''' # 反向解析:返回一个结果 该结果可以访问到对应的路由 # 1.给路由对应关系起别名 path('register/', views.reg, name='reg_view') # 2.使用反向解析语法 html页面 {% url 'reg_view' %} # register 该结果可以访问路由 后端 from django.shortcuts import reverse print(reverse('reg_view')) # register 该结果可以访问路由 # 这个时候不过路由的名称这么改变 前端和后端都可以访问到
四、无名有名反向解析
# 当网址后面有不确定的匹配因素 反向解析的时候需要认为来传值 path('reg/<str:info>/', views.reg, name='reg_view') # 转换器是用来匹配不确定的因素的 而后端和前端需要认为传参才行 eg: ''' reg/jason reg/tony reg/123ab123 上述三个都可以匹配成功能够匹配的名称可以有很多 而这个时候我们用'reg_view'做反向解析的时候不知道解析出来的结果是什么 所以当路由中有不确定因素的时候做反向解析的时候 我们需要手动传参告诉路由匹配的不确定因素是什么 ''' '''.无名有名反向解析''' # 路由层: path('reg/<str:info>/', views.reg, name='reg_view') # 后端和前端都需要 人为传递参数 # 前端 reverse('reg_view', args=('jason',)) print(reverse('reg_view', args=('jason',))) # 这个时候解析出来的结果就是 /reg/jason/ 这个结果就可以访问reg路由 # 后端 {% url 'reg_view' 'jason' %} # 这个时候不确定因素就会被我们固定下来 /reg/jason/ 就可以访问路由reg了 # 如果在正则匹配中给匹配的数据起了别名也是一样的 re_path(r'^func66/(?P<id>\d+)', views.func,name='func_view') 前端: {% url 'func_view' 123 %} # func66/123/ {% url 'func_view' id=123 %} # func66/123/ 后端: from django.shortcuts import reverse reverse('func_view',args=(666,)) # func66/666/ reverse('func_view',kwargs={'id'=1}) # func66/666/
五、路由分发
'''如果一个django项目特别庞大 里面有很多应用 每个应用下有很多对应关系 那么django自带的路由层里面的代码就会非常非常的多 该怎么优化?? 根据应用的不同拆分到不同的应用中 django支持每个应用都可以有自己独立的 路由层、模板层、静态文件、试图层(默认)、模型层(默认) 上述特性能够让django在分组开发上更加的方便、快捷 所有人都可以在应用中开发完整的项目功能 最后汇总到一个空的django项目中 然后通过路由分发整合所有人的应用 ''' # 1.创建多个应用 并去配置文件中注册 INSTALLED_APPS = [ 'app01' 'app02' ] # 2.在多个应用中编写相同的路由 app01中的urls urlpatterns = [ path('after/', views.after) ] app02中的urls urlpatterns = [ path('after/', views.after) ] # 子路由跟试图函数对应 # 3.路由分发 from django.conf.urls import url, include from app01 import urls as app01_urls from app02 import urls as app02_urls path('app01/', include('app01.urls')), path('app02/', include('app02.urls')), '''总路由只负责分发 不负责试图函数对应'''
六、名称空间
# 1.当不同的应用使用了相同的别名 那么反向解析是否自动识别 index_view app01/index/ index_view app02/index/ # 2.验证发现默认情况下是不会自动识别应用前缀的 如何解决反向解析问题 方式1:名称空间 namespace path('app01/', include(('app01.urls', 'app01'), namespace='app01')) path('app01/', include(('app01.urls', 'app02'), namespace='app02')) 前端和后端 reverse('app01:index_view') reverse('app02:index_view') {% url 'app01:index_view' %} {% url 'app02:index_view' %} 方式2:只需要确保反向解析的别名在整个项目中不重复即可!! 可以在别名的前面加上应用名的前缀 url(r'^index/',views.index,name='app01_index_view') url(r'^index/',views.index,name='app02_index_view') """ 保证django项目下没有重复的别名即可 """
七、作业
1.总路由
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('app01/', include('app01.urls')), path('app02/', include('app02.urls')), ]
2.app01
from django.urls import path from app01 import views urlpatterns = [ # 数据展示 path('home/', views.home, name='app01_home_views'), # 新增数据 path('add/', views.add, name='app01_add_view'), ]
3.app02
from django.urls import path from app01 import views urlpatterns = [ # 编辑 path('update/<int:id>/', views.update, name='app02_update_view'), # 删除 path('delete/<int:id>/', views.delete, name='app02_delete_view') ]
4.视图层
def home(request): user_queryset = models.User.objects.filter() return render(request, 'home.html', {'user_queryset': user_queryset}) def add(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') age = request.POST.get('age') is_user = models.User.objects.filter(name=username) if is_user: return HttpResponse('用户名已存在') models.User.objects.create(name=username, pwd=password, age=age) return redirect('app01_home_views') return render(request, 'add.html') def update(request, id): user_queryset = models.User.objects.filter(id=id).first() if request.method == "POST": username = request.POST.get('username') password = request.POST.get('password') age = request.POST.get('age') models.User.objects.filter(id=id).update(name=username, pwd=password, age=age) return redirect('app01_home_views') return render(request, 'update.html', {'user_queryset': user_queryset}) def delete(request, id): models.User.objects.filter(id=id).delete() return redirect('app01_home_views')
五、模板层
<!--home.html--> <div class="content"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <h1 class="text-center">数据展示</h1> <a href="{% url 'app01_add_view' %}" class="btn btn-primary btn-xs">新增用户</a> <table class="table table-hover table-striped"> <thead> <tr> <th>id</th> <th>姓名</th> <th>年龄</th> <th>密码</th> <th class="text-center">操作</th> </tr> </thead> <tbody> {% for user_obj in user_queryset %} <tr> <td>{{ user_obj.id }}</td> <td>{{ user_obj.name }}</td> <td>{{ user_obj.age }}</td> <td>{{ user_obj.pwd }}</td> <td class="text-center"> <a href="{% url 'app02_update_view' user_obj.id %}" class="btn btn-success btn-xs">编辑</a> <a href="{% url 'app02_delete_view' user_obj.id %}" class="btn btn-danger btn-xs">删除</a> </td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> <!--add.html--> <div class="content"> <div class="row"> <h1 class="text-center">新增页面</h1> <div class="col-md-8 col-md-offset-2"> <form action="" method="post"> <p>username: <input type="text" name="username" class="form-control"></p> <p>password: <input type="text" name="password" class="form-control"></p> <p>age: <input type="text" name="age" class="form-control"></p> <p><input type="submit" class="btn btn-success btn-block" value="提交"></p> </form> </div> </div> </div> <!-- update--> <div class="content"> <div class="row"> <h1 class="text-center">编辑页面</h1> <div class="col-md-8 col-md-offset-2"> <form action="" method="post"> <p>username: <input type="text" name="username" class="form-control" value="{{ user_queryset.name }}"></p> <p>password: <input type="text" name="password" class="form-control" value="{{ user_queryset.pwd }}"></p> <p>age: <input type="text" name="age" class="form-control" value="{{ user_queryset.age }}"></p> <p><input type="submit" class="btn btn-success btn-block" value="提交"></p> </form> </div> </div> </div>

浙公网安备 33010602011771号