5.Django(简单登录认证、url路由系统、无名分组、有名分组)

简单登录认证

  • 串一下流程

    浏览器通过输入url发送了给服务器一个请求,这个请求先发送到url路由分发,找到对应的views函数,并且Django将请求信息封装成了一个对象传递给此函数的第一个参数request,执行views视图函数的对应的函数

    最终返回一个页面。

    render:类似于jinja2,模板渲染系统。(作用:接受html页面数据,将想呈现在前端的数据库数据替换掉,形成最终的html并给return 由return返回给浏览器)

  • 构建一个登陆的index.html页面

    当你只是修改了html内容时,再次请求不需要重启项目。

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    <form action="">
      用户名:<input type="text" name="username">
      密 码 :<input type="password" name="password">
      <input type="submit">
    </form>
    </body>
    </html>

    // action 不写默认提交到当前路径
    // form表单默认是get提交

    思考:当点击提交,用户名、密码数据会通过url传递到对应的login函数中,我们应该将数据提取出来。如何提取?

    request将所有的请求信息都接受到了,他肯定有个方法request.GET,但是现在有个问题,我访问这个url(刷新页面)是get请求,返回给我们一个form表单的页面,然后再次通过get请求提交数据

    from django.shortcuts import render
    from django.shortcuts import HttpResponse

    # Create your views here.


    def login(request):
      """
      :param request: 可以设置任意形参,但是第一个参数约定俗称为request与类里面的self同理
      request 接收所有请求相关的信息
      :return:
      """
      if request.GET:
          username = request.GET['username']
          password = request.GET['password']
          if username == '牧羊小董' and password == '123':
              return HttpResponse('登陆成功')
          else:
              return HttpResponse('登录失败')
      else:
          return render(request,'index.html')

    虽然我们上面的功能完成了,但是不合理。一般我们提交数据都是通过post提交。这里为什么我们要请求页面用get而提交数据用post?

    因为你的路径index对应的login函数处理两次请求,如果两次请求都是get或者post,我们在函数中不易区分。

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    <form action="" method="post">
      用户名:<input type="text" name="username">
      密 码 :<input type="password" name="password">
      <input type="submit">
    </form>
    </body>
    </html>



    from django.shortcuts import render
    from django.shortcuts import HttpResponse

    # Create your views here.


    def login(request):
      """
      :param request: 可以设置任意形参,但是第一个参数约定俗称为request与类里面的self同理
      request 接收所有请求相关的信息
      :return:
      """
      if request.method == 'POST':
          username = request.POST.get('username')
          password = request.POST.get('password')
          # get方法比直接用['username']有什么好处?
          # get取值 不存在返回none 不报错 也可设置不存在返回什么
          if username == '牧羊小董' and password == '123':
              return HttpResponse('登录成功')
          else:
              return HttpResponse('登录失败')
      else:
          return render(request,'index.html')

    为什么报一个forbidden错误?通过post向后端请求数据时,需要进行中间件的验证(后面会讲到)我们找到settings将这个中间件先注销掉。

    request的方法:

    request.method  获取请求方式  GET、POST、HEAD、DELETE
    request.GET 获取get请求提交的数据,quertdict类型,类似于字典
    request.POST 获取post请求提交的数据,quertdict类型,类似于字典
    HttpResponse 返回浏览器一个字符串 提示
    render 返回浏览器一个html页面。模板系统

 

url路由系统

url路由系统通过路径映射不同的函数。

  • url格式

    from django.conf.urls inport url

    urlpatterns = [
    url(正则表达式,views视图函数,参数,别名),
    url(正则表达式,views视图函数,参数,别名),
    url(正则表达式,views视图函数,参数,别名),
    url(正则表达式,views视图函数,参数,别名),
    url(正则表达式,views视图函数,参数,别名),
    ]

    url底层遵循轮循机制的:
    # 循环urlpatterns,找到对应的函数执行,匹配上一个路径就找到对应的函数执行,就不再往下循环了,并给函数穿一个参数request,和wsfiref的environ类似,就是请求信息的所有内容
  • 参数说明

    • 正则表达式:一个正则表达式字符串 最前面隐藏了http://ip:端口

    • views视图函数:一个可调用对象,通过为一个视图函数或一个指定视图函数路径的字符串

    • 参数:可选的要传递给视图函数的默认参数(字典形式)

    • 别名:一个可选的name参数

 

无名分组

浏览器访问后端,肯定会遇到传递数据的情况,我们现在已知的给后端传递数据通过form表单,我们还可以通过url路径给后端传递数据。

我们现在做一个图书管理系统,里面存储着全世界前1000的数据,我们还可以检索,我想查询这些书中有没有2000年出版的,我们就做一个这样的流程

urls代码:

"""first_pro URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
  https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
  1. Add an import: from my_app import views
  2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
  1. Add an import: from other_app.views import Home
  2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
  1. Import the include() function: from django.conf.urls import url, include
  2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from chat import views

urlpatterns = [
  url(r'^admin/', admin.site.urls),
  url(r'^index/', views.login),
  url(r'^books/(\d{4})/$',views.books_year),
  # 127.0.0.1:8000/books/任意四个数字/
  url(r'^books/(\d{4})/(\d{1,2})/$', views.books_year_mouth),
  # 127.0.0.1:8000/books/任意1⾄2个数字/
]

views代码:

from django.shortcuts import render
from django.shortcuts import HttpResponse

# Create your views here.

def books(requerst):
  return render(requerst,'books.html')

def books_year(request, year):
  return HttpResponse(f'出版的年份{year}')

def books_year_mouth(request, year, mouth):
  return HttpResponse(f'出版的年份{year},出版⽉份{mouth}')

 

注意事项:

1、urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。

2、若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。只有加上()才能当做实参传递给对应的views函数。

3、不需要添加一个前导的反斜杠(也就是写在正则前面的那个/),因为每个URL都有。例如,应该是^books⽽不是 ^/books。

4、每个正则表达式前面的r是可选的但是建议加上。

5、^books$以什么结尾,以什么开头,严格限制路径。

6、无名分组给对应的views函数传递的是形式参数(或者默认值参数)

 

有名分组

  • 格式

    ?P<参数名字>正则匹配
  • 代码测试:

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', views.login),
        url(r'^books/(?P<year>\d{4})/$', views.books_year),
        url(r'^books/(?P<year>\d{4})/(P<mouth>\d{1,2})$',views.books_year_mouth),
    ]
    
    
    def books_year(request, year):
    	return HttpResponse(f'出版的年份{year}')
    	
    def books_year_mouth(request, year, mouth=12):
    	return HttpResponse(f'出版的年份{year},出版⽉份{mouth}')
    
  • 小结:

    无名分组相当于 函数的位置传参,从左至右一一对应,例如:
    url(r'^books/(\d{4})/(\d{1,2})/$', views.books_year_mouth)
    def books_year_mouth(request,y,n):
    	pass
    books_year_mouth(⾃动传参请求对象,1989,12)
    
    有名扥组相当于 函数的关键字传参,不用按照顺序但是必须一一对应:
    url(r'^books/(?P<year>\d{4})/(?P<mouth>\d{1,2})$', views.books_year_mouth)
    
    def books_year_mouth(request,mouth,year):
    	pass 
    books_year_mouth(⾃动传参请求对象,year=1989,mouth=12)

 

url反向解析

  • 给路径起别名

    url(r'^delete_book/(\d+)/', views.delete_book, name='delete_book') 
  • 为什么要起别名

    比如,后端跳转一个页面:

    redirect('/index/')

    前端,要拼接一个路径:

    <a href="http://127.0.0.1:8000/delete_book/{{ book.id }}" class="btn btn-danger">删除</a>

    我们这个路径都写死了,如果有一天,由于项目需求,要让你更改一下某个业务的url。

  • 这就意味着,无论前端还是后端,只要你用到了之前的路径的所有的代码全部都改。这样的话是没有拓展性的,太low了。所以我们要给url起个别名,以后无论url怎么改动,我们就可以一直使用者别名。

    • 起那段如果使用别名拼接路径?

      <a href="{% url 'delete_book' book.id %}" class="btn btn-danger">删除</a>
    • 后端如何使用起别名?

      如果是通过redirect跳转: redirect('别名')
      redirect('index') # 之所以redirect可以通过别名访问到对应的真实路径,源码内部利用了reverse反向解析,解析除了真正的路径
      redirect(reverse('index')) 多此一举,因为redirect源码内部使用了reverse反向解析。
  • url的反向解析

    引用一个reverse模块

    from django.urls import reverse
    print(reverse('index')) # /check_book/
    通过reverse模块将别名对应的真实路径反向解析出来。
  •  

posted @ 2020-05-19 10:42  牧羊小董  阅读(171)  评论(0)    收藏  举报