一:web框架基础简介
【1】web框架本质
(1)web本质也是C/S架构
(2)浏览器:客户端
(2)服务端:服务端
【2】web框架自定义
import socket server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(6) while True: conn ,addr = server.accept() # 字符串 recv_data = conn.recv(1024).decode('utf-8') print(recv_data) conn.send(b'hello world') conn.close()
(1)客户端结果展示
(2)服务端结果展示
'''b'GET / HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36 Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Sec-Fetch-Site: none Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 '''
PS:客户端无法正常接收数据的原因
(1)首先浏览器向服务端发送请求的时候 这个数据怎么发送 格式是什么样式
(2)不同的网站可能对发送方式定义的不一样 如果太多不一样 导致整个互联网紊乱
(3)因此我们使用同一标准HTTP协议
【3】HTTP协议版本
import socket server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(6) while True: conn ,addr = server.accept() # 字符串 recv_data = conn.recv(1024) # HTTP版本 响应状态码 换行符 conn.send(b'HTTP/1.1 200 OK ') conn.send(b'hello world') conn.close()
二:Web框架修正版
【1】根据用户请求的url不同返回相应的数据
(1)作用:每个用户可能请求的数据不同 根据用户请求的结果不同 返回不同的数据
(2)思路:
(1)首先需要获取用户输入的路径
(2)获取用户的路径根据不同的路径做不同从处理
例如:
import socket server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(6) while True: conn, addr = server.accept() # 拿到用户传入的数据 将其转为字符串状态 recv_data = conn.recv(1024).decode('utf-8') print(recv_data) # 字符串 # 将获取的字符串进行切割获取列表 path_list = recv_data.split(' ')[0] # 列表取索引获取访问路径 current_path = path_list.split(' ')[1] print(current_path) # /index # 根据HTTP协议进行数据交互 conn.send(b'HTTP/1.1 200 OK ') # 根据访问路径不同 返回不同的结果 if current_path == '/index': conn.send(b'index') elif current_path == '/home': conn.send(b'home') # 访问资源不存 返回404 else: conn.send(b'404 error')
''' D:Softwarespython3.6python.exe "E:/work station/day51/django基础版本.py" 请求首行 GET / HTTP/1.1 请求头 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36 Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Sec-Fetch-Site: cross-site Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 请求体:用户没传入 # conn.send(b'HTTP/1.1 200 OK ')
【2】路由与视图函数对应关系
(1)作用:
(1)上述代码解决了根据不同的url返回不同的结果
(2)但是假如有多个条件语句 需要写大量的条件判断 这样肯定是不合理的
(2)解决办法
(1)创建路由与函数的对应关系 通过路由来执行不同的功能
例如:
import socket server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(6) def index(current_path): response = f'hello{current_path}' # 将字符串转换成二进制传输 return bytes(response,encoding='utf-8') def home(current_path): response = f'hello{current_path}' return bytes(response, encoding='utf-8') # 创建路由与视图函数关系 以后添加新的功能 直接添加路由与对应的视图函数即可 url_list = [ ('/index', index), ('/home', home) ] while True: conn, addr = server.accept() # 拿到用户传入的数据 将其转为字符串状态 recv_data = conn.recv(1024).decode('utf-8') # 将获取的字符串进行切割获取列表 path_list = recv_data.split(' ')[0] # 列表取索引获取访问路径 current_path = path_list.split(' ')[1] # 根据HTTP协议进行数据交互 conn.send(b'HTTP/1.1 200 OK ') func = None # 循环打印上述路由与视图关系列表 for url in url_list: # 如果用户的url路径在上述列表中 if url[0] == current_path: # 给上述函数赋值 func = url[1] # 函数赋值之后 不需要再继续进行循环 直接打印即可 break # 如果上函数被赋值 则调用函数 if func: res = func(current_path) else: res = b'404 error' # 返回消息给客户端 conn.send(res) conn.close()
三:动静态网页传递
(1)定义:
(1)静态网页:数据是固定不变的
(2)动态网页:数据是是可灵活变化的
(2)作用:
(1)在上述代码中我们返回一些无用的字符串呈现给用户
(2)在网页传递过程中我们传递相应的HTML文件呈现给用户
例如:
import socket server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(60) def index(): # 对于python来说什么文件都是二进制 直接读取发送即可 with open(r'ht1.html', 'rb') as file: data = file.read() return data def home(): with open(r'ht1.html', 'rb') as file: data = file.read() return data url_dict = { '/index': index, '/home': home } while True: conn, addr = server.accept() recv_data = conn.recv(1024).decode('utf-8') url_list = recv_data.split(' ')[0] url_path = url_list.split(' ')[1] conn.send(b'HTTP/1.1 200 OK ') func = None for key, value in url_dict.items(): if key == url_path: func = url_dict.get(key) break if func: res = func() else: res = b'404 error' conn.send(res) conn.close()
import socket server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(66) from datetime import datetime func = None def index(): now_time = datetime.now().strftime('%Y-%m-%d %X') with open(r'h2.html', 'r', encoding='utf-8') as f: data = f.read() # 读取HTML中的数据 将其替换成我们想要传给用户的数据 这样类似于我们将后端数据插入到HTML数据中 time = data.replace('SR', now_time).encode('utf-8') return time def home(): now_time = datetime.now().strftime('%Y-%m-%d %X') with open(r'h2.html', 'r', encoding='utf-8') as f: data = f.read() # 读取HTML中的数据 将其替换成我们想要传给用户的数据 这样类似于我们将后端数据插入到HTML数据中 time = data.replace('SR', now_time).encode('utf-8') return time url_list = { '/index': index, '/home': home } while True: conn, addr = server.accept() recv_data = conn.recv(1024).decode('utf-8') conn.send(b'HTTP/1.1 200OK ') # 获取url地址 url_path = recv_data.split(' ')[0].split(' ')[1] for key, value in url_list.items(): if key == url_path: func = url_list.get(key) break if func: res = func() else: res = b'404 error' conn.send(res) conn.close()
四:服务器程序和应用程序
对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。
服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。
应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。
这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。
这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。
WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。
常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。
五:WSGI/jinja2基本使用方式
【1】wsgi
(1)作用:
(1)可以利用该模块替换我们自己写的socket server部分
(2)将客户端传入的数据拆封成字典
(3)将服务端传入给客户端的数据封装携带含有HTTP协议
例如:
# 导入模块 from wsgiref.simple_server import make_server def index(): data = b'hello world!' return data def home(): data = b'hello world!' return data url_list = { '/index': index, '/home': home } def run_server(request, response): ''' 与客户端进行数据交互的函数 :param request: 用户请求数据 :param response: 服务端回应数据 :return: ''' print(request) # 用户传来的数据自动变成字典格式 response('200 ok', []) # 回应客户端的格式 url_path = request.get('PATH_INFO') func = None for key,value in url_list.items(): if key == url_path: func = url_list.get(key) break if func: res = func() else: res = b'404 error' return [res] if __name__ == '__main__': # 监听该地址加上端口号 如果有请求 直接调用该函数 server = make_server('127.0.0.1', 8080, run_server) # 启动服务端 server.serve_forever()
【2】jinja2与html结合
(1)作用:将后端传递给前端的数据进行页面渲染
例如:
import pymysql from jinja2 import Template from wsgiref.simple_server import make_server def mysql(): conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123', database='day51', charset='utf8', autocommit=True ) cursor = conn.cursor(pymysql.cursors.DictCursor) sql = "select * from user_info" affect_rows = cursor.execute(sql) data = cursor.fetchall() with open(r'my_sql.html','r',encoding='utf-8') as f: recv_data = f.read() temp = Template(recv_data) res = temp.render(user_list=data).encode('utf-8') return res url_list = { '/mysql': mysql, } def run(request, response): url_path = request['PATH_INFO'] response('200 ok', []) func = None for key, value in url_list.items(): if key == url_path: func = url_list.get(key) break if func: res = func() else: res = b'404 error' return [res] if __name__ == '__main__': server = make_server('127.0.0.1', 8080, run) print('启动') server.serve_forever()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <h2 class="text-center">用户数据展示</h2> <table class="table table-hover table-bordered table-striped"> <thead> <tr> <th class="text-center">id</th> <th class="text-center">username</th> <th class="text-center">age</th> </tr> </thead> <tbody> {%for user_dict in user_list%} <tr> <td class="text-center">{{user_dict.id}}</td> <td class="text-center">{{user_dict.name}}</td> <td class="text-center">{{user_dict.age}}</td> </tr> {%endfor%} </tbody> </table> </div> </div> </div> </body> </html>
六:Django安装使用
【1】命令行安装启动
(1)Django安装
pip3 install django=1.11.11
(2)检查Django是否安装成功
Django-admin
(3)创建Django项目
Django-admin startproject + 项目名称
(4)Django目录介绍
mysite/ ├── manage.py # 管理文件 └── mysite # 项目目录 ├── __init__.py ├── settings.py # 配置 ├── urls.py # 路由 --> URL和函数的对应关系 └── wsgi.py # runserver命令就使用wsgiref模块做简单的web server
(5)创建Django应用
django-admin startapp + 应用名 python manage.py startapp + 应用名
(6)目录应用介绍
└── migrations # 数据库迁移记录 ├── admin.py # 后台管理 ├── apps.py # 应用注册相关 ├── models.py # orm模型类 └── test.py # 测试文件 └── views.py # 视图函数
(6)启动Django服务
Django-admin manage.py runserver
PS:
(1)命令行创建Django项目不会自动生成templates文件夹
(2)settings配置文件中也需要修改
(3)创建的项目需要在配置文件注册生效 否则无识别
七:Django基础三件套
from django.shortcuts import HttpResponse, render, redirect
(1)HttpResponse
作用:内部输入字符串 返回给浏览器
例如:
def index(request): # 业务逻辑代码 return HttpResponse("hello world")
(2)render
作用:
(1)接受一个需要渲染的文件以及字典
(2)将数据填充进模板文件 返回给前端
例如:
def index(request): # 业务逻辑代码 return render(request, "index.html", {"name": "alex", "hobby": ["烫头", "泡吧"]})
PS:其前端接受取值 只能通过.的方式进行取值
(3)redirect
作用:接受一个url地址 跳转到另外一个地址
例如:
def index(request): # 业务逻辑代码 return redirect("/home/")