第十二章 Django框架开发

12.1 HTTP协议

12.1.1 HTTP简介

  1. 超文本传输协议 Hyper Text Transfer Protocol
  2. 是一种用于分布式、协作式和超媒体信息系统的应用层协议
  3. HTTP是万维网的数据通信的基础
  4. HTTP有很多应用,但最著名的是用于web浏览器和web服务器之间的双工通信
  5. HTTP是一个客户端终端和服务器端请求和响应的标准

12.1.2 HTTP 请求/响应的步骤

  1. 客户端连接到Web服务器
    • 一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接
  2. 1579000220427
  3. 发送HTTP请求
    • 通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求首行(\r\n分隔)、请求头部、空行(\r\n\r\n)和请求数据4部分组成
  4. 1579000252365
  5. 服务器接受请求并返回HTTP响应
    • Web服务器解析请求,定位请求资源,服务器将资源复本写到TCP套接字,由客户端读取,一个响应由状态行、响应头部、空行和响应数据4部分组成
  6. 释放连接TCP连接
    • 若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求
  7. 客户端浏览器解析HTML内容
    • 客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码,然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集,客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示
  8. 面试题:在浏览器地址栏键入URL,按下回车之后会经历的流程:
    • 浏览器向DNS服务器请求解析该URL中的域名所对应的IP地址
    • 解析出IP地址后,根据该IP地址和默认端口80,和服务器建立TCP连接
    • 浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP请求,该请求报文作为TCP三次握手的第三个报文的数据发送给服务器
    • 服务器对浏览器请求作出响应,并把对应的html文本发送给浏览器
    • 释放TCP连接
    • 浏览器将该html文本并显示内容

12.1.3 HTTP请求方法

  1. GET:获取一个页面、图片(资源)
  2. POST:提交数据
  3. HEAD
  4. PUT
  5. DELETE
  6. TRACE
  7. OPTIONS
  8. CONNECT

请求方式: get与post请求

  • GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的Body中.
  • GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
  • GET与POST请求在服务端获取请求数据方式不同。
  • GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.

12.1.4 HTTP状态码

1.状态代码的第一个数字代表当前响应的类型:

1579000851375

12.1.5 URL:统一资源定位符

  1. URL包含的信息:
    • 传送协议
    • 层级URL标记符号(为 // ,固定不变)
    • 访问资源需要的凭证信息(可省略)
    • 服务器(通常为域名,有时为IP地址)
    • 端口号(以数字方式表示,可省略,HTTP的默认值为80,HTTPS的默认值为443)
    • 路径(以 / 字符区别路径中的每一个目录名称)
    • 查询(GET模式的窗体参数,以 ? 字符为起点,每个参数以 & 隔开,再以 = 分开参数名称与数据,通常以UTF8的URL编码,避开字符冲突的问题)
    • 片段(以“#”字符为起点)
  2. 示例:http://www.luffycity.com:80/news/index.html?id=250&page=1
    • http,是传送协议
    • www.luffycity.com,是服务器
    • 80,是服务器上的网络端口号
    • /news/index.html,是路径
    • ?id=250&page=1,是查询

12.2 Web框架

12.2.1 Web框架本质

  • 所有的web应用本质是就是一个socket服务器,而用户的游览器就是一个socket客户端

12.2.2 Web框架功能

  1. socket收发消息 —— wsgiref(测试)、uwsgi(线上)
  2. 根据不同的路径返回不同的字符串
  3. 返回动态页面(字符串的替换)—— jinja2

12.2.3 Web框架种类

  1. django
    • 根据不同的路径返回不同的字符串
    • 返回动态页面(字符串的替换)
  2. flask
    • 根据不同的路径返回不同的字符串
  3. tornado
    • socket收发消息
    • 根据不同的路径返回不同的字符串
    • 返回动态页面(字符串的替换)

12.2.4 自定义web框架

  1. 示例一:socket服务端

    import socket
    # 创建一个socket对象
    sk = socket.socket()
    # 绑定IP和端口
    sk.bind(('127.0.0.1', 8000))
    # 监听
    sk.listen(5)
    # 等待连接
    while True:
        conn, addr = sk.accept()
        # 接收数据
        data= conn.recv(1024)
        print(data)
        # 返回数据
        conn.send(b'HTTP/1.1 200 OK\r\n\r\n<h1>ok!</h1>')
        # 断开连接
        conn.close()
  2. 示例二:根据不同路径返回不同的内容(普通版)

    import socket
    # 创建一个socket对象
    sk = socket.socket()
    # 绑定IP和端口
    sk.bind(('127.0.0.1', 8000))
    # 监听
    sk.listen(5)
    # 等待连接
    while True:
        conn, addr = sk.accept()
        # 接收数据
        data = conn.recv(1024)
        data = data.decode('utf-8')
        url = data.split()[1]
        conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
        if url == '/index/':
            # 返回数据
            conn.send(b'<h1>index!</h1>')
        elif url == '/home/':
            conn.send(b'<h1>home!</h1>')
        else:
            conn.send(b'<h1>404 not found!</h1>')
        # 断开连接
        conn.close()
  3. 示例三:根据不同路径返回不同的内容(函数版)

    import socket
    # 创建一个socket对象
    sk = socket.socket()
    # 绑定IP和端口
    sk.bind(('127.0.0.1', 8000))
    # 监听
    sk.listen(5)
    # 函数
    def index(url):
        ret = '<h1>index!</h1>({})'.format(url)
        return ret.encode('utf-8')
    def home(url):
        ret = '<h1>home!</h1>({})'.format(url)
        return ret.encode('utf-8')
    # 等待连接
    while True:
        conn, addr = sk.accept()
        # 接收数据
        data = conn.recv(1024)
        data = data.decode('utf-8')
        url = data.split()[1]
        conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
        if url == '/index/':
            # 返回数据
            ret = index(url)
        elif url == '/home/':
            ret = home(url)
        else:
            ret = b'<h1>404 not found!</h1>'
        conn.send(ret)
        # 断开连接
        conn.close()
  4. 示例四:根据不同路径返回不同的内容(函数进阶版)

    import socket
    # 创建一个socket对象
    sk = socket.socket()
    # 绑定IP和端口
    sk.bind(('127.0.0.1', 8000))
    # 监听
    sk.listen(5)
    # 函数
    def index(url):
        ret = '<h1>index!</h1>({})'.format(url)
        return ret.encode('utf-8')
    def home(url):
        ret = '<h1>home!</h1>({})'.format(url)
        return ret.encode('utf-8')
    # 定义一个list1和实际要执行的函数的对应关系 
    list1 = [
        ('/index/', index),
        ('/home/', home),
    ]
    # 等待连接
    while True:
        conn, addr = sk.accept()
        # 接收数据
        data = conn.recv(1024)
        data = data.decode('utf-8')
        url = data.split()[1]
        conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
        func = None
        for i in list1:
            if url == i[0]:
                func = i[1]
                break
        if func:
            ret = func(url)
        else:
            ret = b'<h1>404 not found!</h1>'
        conn.send(ret)
        # 断开连接
        conn.close()
  5. 示例五:返回HTML页面

    import socket
    # 创建一个socket对象
    sk = socket.socket()
    # 绑定IP和端口
    sk.bind(('127.0.0.1', 8000))
    # 监听
    sk.listen(5)
    # 函数
    def index(url):
        with open('index.html','rb') as f:
            ret = f.read()
        return ret
    def home(url):
        ret = '<h1>home!</h1>({})'.format(url)
        return ret.encode('utf-8')
    # 定义一个list1和实际要执行的函数的对应关系
    list1 = [
        ('/index/', index),
        ('/home/', home),
    ]
    # 等待连接
    while True:
        conn, addr = sk.accept()
        # 接收数据
        data = conn.recv(1024)
        data = data.decode('utf-8')
        url = data.split()[1]
        conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
        func = None
        for i in list1:
            if url == i[0]:
                func = i[1]
                break
        if func:
            ret = func(url)
        else:
            ret = b'<h1>404 not found!</h1>'
        conn.send(ret)
        # 断开连接
        conn.close()
  6. 示例六:返回动态页面

    import socket
    import time
    # 创建一个socket对象
    sk = socket.socket()
    # 绑定IP和端口
    sk.bind(('127.0.0.1', 8000))
    # 监听
    sk.listen(5)
    # 函数
    def index(url):
        with open('index.html', 'rb') as f:
            ret = f.read()
        return ret
    def home(url):
        ret = '<h1>home!</h1>({})'.format(url)
        return ret.encode('utf-8')
    def timer(url):
        now = time.strftime('%H:%M:%S')
        with open('time.html','r',encoding='utf-8') as f:
            data = f.read()
        data = data.replace('xxtimexx',now)
    
        return data.encode('utf-8')
    # 定义一个list1和实际要执行的函数的对应关系
    list1 = [
        ('/index/', index),
        ('/home/', home),
        ('/time/', timer),
    ]
    # 等待连接
    while True:
        conn, addr = sk.accept()
        # 接收数据
        data = conn.recv(1024)
        data = data.decode('utf-8')
        url = data.split()[1]
        conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
        func = None
        for i in list1:
            if url == i[0]:
                func = i[1]
                break
        if func:
            ret = func(url)
        else:
            ret = b'<h1>404 not found!</h1>'
        conn.send(ret)
        # 断开连接
        conn.close()
    • 补充:time.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
         <h1>当前时间是:@@time@@</h1>
      </body>
      </html>

12.2.5 wsgiref

  1. 常用的WSGI服务器有uWSGI、Gunicorn

    • Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器
  2. 示例:

    """  
    根据URL中不同的路径返回不同的内容--函数进阶版  
    返回HTML页面  
    让网页动态起来  
    wsgiref模块版  
    """       
    from wsgiref.simple_server import make_server     
    
    # 将返回不同的内容部分封装成函数   
    def index(url):   
        # 读取index.html页面的内容   
        with open("index.html", "r", encoding="utf8") as f:   
            s = f.read()   
        # 返回字节数据   
        return bytes(s, encoding="utf8")       
    
    def home(url):   
        with open("home.html", "r", encoding="utf8") as f:   
            s = f.read()   
        return bytes(s, encoding="utf8")       
    
    def timer(url):   
        import time   
        with open("time.html", "r", encoding="utf8") as f:   
            s = f.read()   
            s = s.replace('@@time@@', time.strftime("%Y-%m-%d %H:%M:%S"))   
        return bytes(s, encoding="utf8")        
    
    # 定义一个url和实际要执行的函数的对应关系   
    list1 = [   
        ("/index/", index),   
        ("/home/", home),   
        ("/time/", timer),   
    ]        
    
    def run_server(environ, start_response):   
        start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息   
        url = environ['PATH_INFO']  # 取到用户输入的url   
        func = None   
        for i in list1:   
            if i[0] == url:   
                func = i[1]   
                break   
        if func:   
            response = func(url)   
        else:   
            response = b"404 not found!"   
        return [response, ]      
    
    if __name__ == '__main__':   
        httpd = make_server('127.0.0.1', 8090, run_server)   
        print("我在8090等你哦...")   
        httpd.serve_forever()  

12.2.6 jinja2

  1. 模板渲染现成的工具:jinja2

    • 下载jinja2:pip install jinja2
  2. 示例:

    from wsgiref.simple_server import make_server  
    from jinja2 import Template    
    
    def index(url):  
        # 读取HTML文件内容  
        with open("index2.html", "r", encoding="utf8") as f:  
            data = f.read()  
            template = Template(data)   # 生成模板文件 
            ret = template.render({'name': 'alex', 'hobby_list': ['抽烟', '喝酒', '烫头']})   # 把数据填充到模板中  
        return bytes(ret, encoding="utf8")  
    
    def home(url):  
        with open("home.html", "r", encoding="utf8") as f:  
            s = f.read()  
        return bytes(s, encoding="utf8")  
    
    # 定义一个url和实际要执行的函数的对应关系  
    list1 = [  
        ("/index/", index),  
        ("/home/", home),  
    ]   
    
    def run_server(environ, start_response):  
        start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息  
        url = environ['PATH_INFO']  # 取到用户输入的url  
        func = None  
        for i in list1:  
            if i[0] == url:  
                func = i[1]  
                break  
        if func:  
            response = func(url)  
        else:  
            response = b"404 not found!"  
        return [response, ]  
    
    if __name__ == '__main__':  
        httpd = make_server('127.0.0.1', 8090, run_server)  
        print("我在8090等你哦...")  
        httpd.serve_forever() 
    • 补充:index2.html

      <!DOCTYPE html>
      <html lang="zh-CN">
      <head>
          <meta charset="UTF-8">
          <meta http-equiv="x-ua-compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>Title</title>
      </head>
      <body>
          <h1>姓名:{{name}}</h1>
          <h1>爱好:</h1>
          <ul>
              {% for hobby in hobby_list %}
                 <li>{{hobby}}</li>
              {% endfor %}
          </ul>
      </body>
      </html>

12.3 Django基本知识

12.3.1 安装及使用

  1. 下载安装

    • 命令行:pip3 install django==1.11.21
    • pycharm
  2. 创建项目

    • 命令行:
      • 找一个文件夹存放项目文件,打开终端:
      • django-admin startproject 项目名称
      • 项目目录
    • pycahrm
  3. 启动

    • 命令行
      • 切换到项目的根目录下 manage.py
      • python36 manage.py runserver —— 127.0.0.1:80`
      • python36 manage.py runserver 80——127.0.0.1:80
      • python36 manage.py runserver 0.0.0.0:80——0.0.0.0:80
    • pycharm:点绿三角启动 可配置
  4. 简单使用

    • 示例:返回HTML指定文件
    # 在urls.py中
    # 导入
    from django.shortcuts import HttpResponse,render
    
    # 函数
    def index(request):
        # return HttpResponse('index')
        return render(request,'index.html')
    
    # url和函数对应关系
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', index),
    ]

12.3.2 静态文件

  1. 配置

    • 在settings.py中设置
    STATIC_URL = '/static/'           # 别名
    STATICFILES_DIRS = [         # 设置文件路径,可以设置多个
        os.path.join(BASE_DIR, 'static1'),
        os.path.join(BASE_DIR, 'static'),
        os.path.join(BASE_DIR, 'static2'),
    ]    
  2. 使用

    • 在路径前添加别名:/static/
    • 多个文件路径,也是使用同一个别名,不是文件名
    • 如果别名后的路径名相同,按照STATICFILES_DIRS列表的顺序进行查找
    <link rel="stylesheet" href="/static/css/login.css">          {# 别名开头 #}

12.3.3 简单的登录实例

  1. form表单提交数据注意的问题:

    • 提交的地址:action="",请求的方式:method="post"
    • 所有的input框有name属性,如name="username"
    • 有一个input框的type="submit"或者有一个button
  2. 提交post请求,由于Django中有一个csrf校验,所有请求会出问题

    • 解决方式:把settings中MIDDLEWARE的'django.middleware.csrf.CsrfViewMiddleware'注释掉
    • 或者在html 页面form表单下写 {% csrf_token %}
  3. 重定向

    • 导入方式

    • from django.shortcuts import redirect
    • 使用方式

    • 在函数中使用:
      return redirect('/index/')  #参数 url
      #注意:前面必须加/,代表从url根拼接,否则就会在当前url后面一直拼接
  4. 示例:

    from django.shortcuts import HttpResponse, render, redirect
    
    def index(request):
        # return HttpResponse('index')
        return render(request, 'index.html')
    
    def login(request):
        if request.method == 'POST':
            # 获取form表单提交的书籍
            username = request.POST['username']
            password = request.POST['password']
            # 验证用户名和密码
            if models.User.objects.filter(username=username,password=password):
                # 验证成功跳转到index页面
                # return redirect('https://www.baidu.com/')
                return redirect('/index/')
            # 不成功 重新登录
        return render(request, 'login.html')
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', views.index),
        url(r'^login/', views.login),
    ]

12.3.4 app

  1. 创建app

    • 命令行:python manage.py startapp app名称
    • pycharm:tools --> run manage.py task --> 输入命令:startapp app名称
  2. 注册app

    • 在settings.py中设置,例:app名为app01
    INSTALLED_APPS = [
     ...
        'app01',
        'app01.apps.App01Config',        # 推荐写法
    ]
  3. app中的文件

    • migrations:存放迁移文件的
    • admin.py:Django提供的后台管理工具
    • app.py:与app信息相关的
    • models.py:跟ORM有关的内容
    • views.py:视图,写函数的

12.3.5 使用MySQL流程

  1. 创建一个MySQL数据库:create database day53;

  2. 在settings.py中设置,Django连接MySQL数据库:

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',      # 引擎  
            'NAME': 'day53',                      # 数据库名称
            'HOST': '127.0.0.1',                  # ip地址
            'PORT':3306,                         # 端口
            'USER':'root',                           # 用户
            'PASSWORD':'123'                     # 密码
        }
    }
  3. 在与settings,py同级目录下的init文件中写入:

    import pymysql
    pymysql.install_as_MySQLdb()
  4. 创建表(在app下的models.py中写类):

    from django.db import models
    
    class User(models.Model):
        username = models.CharField(max_length=32)        # username varchar(32)
        password = models.CharField(max_length=32)    # username varchar(32)
  5. 执行数据库迁移的命令:

    • python manage.py makemigrations:检测每个注册app下的model.py,记录model的变更记录
    • python manage.py migrate:同步变更记录到数据库中

12.3.6 MVC和MTV

  1. MVC
    • M: model 模型 —— 和数据库打交道
    • V:view 视图 —— HTML
    • C: controller 控制器 —— 调度 传递指令 业务逻辑
  2. MTV:
    • M: model 模型 ORM —— 和数据库打交道
    • T: tempalte 模板 —— HTML
    • V:view 视图 —— 函数 业务逻辑
  3. djando是MTV模式

1579003161902

12.4 Django模板系统:Template

12.4.1 模板常用语法

  • 特殊符号:
    • 变量:{{ }}
    • 标签tag:{% %}

猜你喜欢

转载自www.cnblogs.com/hanfe1/p/12194618.html