自创Web框架之过度Django框架

Web框架,其实就是Web应用的建立;比如网页版的QQ,b站····都是Web应用软件;

Web应用又是什么?可以理解为基于浏览器的一些应用程序,用户只需要有浏览器即可,不需要再安装其他软件;

比如我们打开一个URL,Web服务器返回一个HTML页面给你,那么你在搜索或者URL拼接路径搜索的时候Web服务器是怎么知道要返回什么给你?下面介绍一下:

在介绍之前先介绍所需基础知识,同时也是Web运行所需的:

[Web基础知识](Web入门 - HammerZe - 博客园 (cnblogs.com))

软件开发架构

  • C/S架构:客户端和服务端
  • B/S架构:浏览器和服务端

ps:b/s本质也是c/s架构

HTTP协议

四大特性

  • 基于TCP、IP作用于应用层之上的协议
  • 基于请求响应
  • 无状态
  • 无(短)连接
    • 长连接:websocket

数据格式

请求首行(http协议版本,网络请求的方法)
请求头(一大堆k,v键值对)
/r/n # 换行符不能省略
请求体(存放的是一些数据,并不是每种请求方式都有请求体,get没有请求体,post有请求体) # 请求方式
get:朝服务器索要数据,比如输入网址获得相应的数据
post:向服务器提交数据,比如用户登录输入用户名和密码后,提交到后端做身份校验

响应格式

响应首行(http协议版本,网络请求的方法)
响应头(一大堆k,v键值对)
/r/n # 换行符不能省略
响应体(交给给浏览器展示给用户看的数据)

响应状态码

HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型。响应分为五类:信息响应(100–199),成功响应(200–299),重定向(300–399),客户端错误(400–499)和服务器错误 (500–599)

分类 分类描述
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误
# 注意
公司还会自定义状态码 一般以10000开头
参考:聚合数据

请求方式

  • get请求:向别人(服务器)索要数据
  • post请求:向别人提交数据(比如表单)

Web框架之“撸起袖子加油干”

为了更方便的理解请求网页并返回数据的过程,写一套下面的程序帮助理解

import socket

server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5) # 池子 while True:
conn,addr = server.accept()
data=conn.recv(1024)
# print(data) # 忽略favicon.ico,拿到用户在url后面输入的字符串
data = data.decode('utf-8')
conn.send(b'HTTP/1.1 200 Ok\r\n\r\n')
# 获取字符串中特定的内容 正则和切割
current_path = data.split(' ')[1]
# print(current_path) # /index
if current_path =='/index':
with open(r'E:\web组件\图书管理系统界面\图书管理系统.html','rb')as f:
conn.send(f.read())
elif current_path == '/login':
conn.send(b'hello')
else:
conn.send(b'Nothing to give you!')
conn.close()

通过上面的例子,能够简单的理解通过get请求方式得到的页面是如何返回,但是我们个人手写得服务端存在问题,如果客户请求不同得页面那么我们就得写n多个if/else,数据得格式处理起来也比较繁琐······通过一个模块来解决这些问题wsgiref模块

Web框架之通过wsgiref加油干

# 解决了上述两个问题
from wsgiref.simple_server import make_server def run(request,response):
"""
:param request:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
"""
response('200 OK',[])
current_path = request.get("PATH_INFO")
if current_path == '/index':
return [b'index']
elif current_path == '/login':
return [b'login']
return [b'404 error'] if __name__ == '__main__':
server = make_server('127.0.0.1',8080,run) # 实时监听,一旦被访问会全部交给run函数处理
server.serve_forever() # 启动服务端

封装优化处理

封装的过程中主要解决:

网址的匹配问题

网址多匹配如何解决

功能复杂代码块如何解决,放在一个文件结构不清晰

'''服务端'''
from wsgiref.simple_server import make_server
from views import *
from urls import *
'''
urls.py 路由与视图函数的对应关系
views.py主要存视图函数
templates 文件夹主要存HTML文件
拆分功能后只需在urls.py中书写对应关系,views.py中书写后端的业务逻辑即可
''' def run(env, response):
''' :param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
'''
# print(env) # wsgiref 模块 将http格式的数据处理好
response('200 ok',[])
# 从env返回的大字典中拿出用户输入的内容 --->key
current_path = env.get('PATH_INFO')
# if current_path == '/index':
# return [b'Hell index']
# elif current_path == 'login':
# return [b'hello wsgiref']
# else:
# return [b'404'] # 定义一个变量存储匹配到的函数名
func = None
for url in urls:
if current_path == url[0]:
# 匹配成功将url对应的函数名赋值给func
func = url[1]
break # 结束当前循环
# 判断一下func是否有值
if func:
res = func()
else:
res = error()
return [res.encode('utf-8')] if __name__ == '__main__':
server = make_server('127.0.0.1', 8081, run) # 实时监听,只要有客户端来了,就交给run函数执行
server.serve_forever() # 启动服务端
'''
urls.py 路由与视图函数的对应关系 '''
from views import * urls = [
('/index',index),
('login',login)
]
'''
views.py主要存视图函数
下面统称为视图函数 ''' def index(env):
return 'index'
def login(env):
return 'login'
def error(env):
return '404'
# 返回文件
def file(env):
with open(r'E:\web组件\图书管理系统界面\图书管理系统.html','r',encoding='utf8')as f:
return f.read()

动静网页

  • 静态网页:数据是不变的,不需要实时变化的,数据写死··
  • 动态网页:数据来源于后端(代码、数据库),数据实时变化等特点

示例一:将时间同步到html页面

'''服务端'''
from wsgiref.simple_server import make_server from urls import *
def run(env, response):
''' :param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
'''
# print(env) # wsgiref 模块 将http格式的数据处理好
response('200 ok', [])
# 从env返回的大字典中拿出用户输入的内容 --->key
current_path = env.get('PATH_INFO') # 定义一个变量存储匹配到的函数名
func = None
for url in urls:
if current_path == url[0]:
# 匹配成功将url对应的函数名赋值给func
func = url[1]
break # 结束当前循环
# 判断一下func是否有值
if func:
res = func(env)
else:
res = error(env)
return [res.encode('utf-8')] if __name__ == '__main__':
server = make_server('127.0.0.1', 8081, run) # 实时监听,只要有客户端来了,就交给run函数执行
server.serve_forever() # 启动服务端 '''urls.py'''
from views import * urls = [
('/get_time',get_time),
] '''views.py'''
# 同步时间
def get_time(env):
from datetime import datetime
current_time = datetime.now().strftime('%Y-%m-%d %X')
with open(r'get_time.html','r',encoding='utf8') as f:
data = f.read()
data = data.replace('AAA',current_time) # 用替换的方式将数据传到HTML文件中
return data
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<style>
#d1{
font-size: 48px;
color: tomato; }
</style>
<body> <div class="container">
<div class="row">
<div id="d1" class="col-md-8 col-lg-offset-2">
AAA
</div>
</div>
</div>
</body>
</html>

jinjia2模块

该模块是flask框架必备的模块,在这里只使用jinjia2模块来写我们的模板语法

需求:将后端字典展示到HTML页面上

'''服务端和上面一样'''

'''urls.py'''
from views import *
urls = [
('/get_dict',get_dict)
]
'''views.py''' # 获取字典
def get_dict(env):
user_dict = {'id': 1, 'name': 'Hammer', 'hobby': 'python'}
from jinja2 import Template
with open(r'templates/get_dict.html', 'r', encoding='utf8') as f1:
data = f1.read()
temp = Template(data)
res = temp.render(user_data=user_dict) # 将user_dict传递给html页面,在该页面使用user_data调用
return res
<!--由于导入了jinjia2模块,这里可以直接使用模板语法,类似python的字典方法-->
<body>
{{user_data}}
{{user_data.id}}
{{user_data['name']}}
{{user_data.get('hobby')}}
</body>

数据库

需求:操作MySQL数据并且展示到HTML页面上

注意:数据是在后端处理完之后发送到前端的

'''服务端'''
from wsgiref.simple_server import make_server from urls import *
def run(env, response):
''' :param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
'''
# print(env) # wsgiref 模块 将http格式的数据处理好
response('200 ok', [])
# 从env返回的大字典中拿出用户输入的内容 --->key
current_path = env.get('PATH_INFO') # 定义一个变量存储匹配到的函数名
func = None
for url in urls:
if current_path == url[0]:
# 匹配成功将url对应的函数名赋值给func
func = url[1]
break # 结束当前循环
# 判断一下func是否有值
if func:
res = func(env)
else:
res = error(env)
return [res.encode('utf-8')] if __name__ == '__main__':
server = make_server('127.0.0.1', 8081, run) # 实时监听,只要有客户端来了,就交给run函数执行
server.serve_forever() # 启动服务端
'''路由'''
from views import *
urls = [
('/get_db',get_db)
]
'''视图函数'''
# 获取数据库的内容
def get_db(env):
import pymysql
conn = pymysql.connect(
user='root',
password='7410',
port=3306,
host='127.0.0.1',
database='info',
charset='utf8',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select * from emp;'
rows = cursor.execute(sql)
res = cursor.fetchall() # [{},{},{}]
# print(res)
with open(r'templates/get_db.html','r',encoding='utf8') as f:
data = f.read()
temp = Template(data)
total_res = temp.render(data_list = res)
return total_res
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<h1 style="text-align: center">用户数据</h1>
<div class="col-md-8 col-lg-offset-2">
<table class="table table-striped table-hover ">
<thead>
<tr class="success" style="text-align: center">
<td>id</td>
<td>name</td>
<td>sex</td>
<td>age</td>
<td>dep_id</td>
</tr>
</thead>
<tbody>
{%for user_dict in data_list%}
<tr class="info" style="text-align: center">
<td>{{user_dict.id}}</td>
<td>{{user_dict.name}}</td>
<td>{{user_dict.sex}}</td>
<td>{{user_dict.age}}</td>
<td>{{user_dict.dep_id}}</td>
</tr>
{%endfor%}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>

到此前后端和数据库交互就都完成了,这所有的功能都可以用Django完成,上面只是一个推导过程~


自写框架梳理

  • wsgiref模块:

    • 封装了socket代码
    • 处理了http数据格式
  • 根据功能的不同拆分成不同的文件夹
    • urls.py 路由与视图函数对应关系
    • views.py 视图函数
    • templates 模板文件夹
  • 步骤:
    • 第一步添加路由与视图函数的对应关系
    • 去views中书写功能代码
    • 如果需要使用到html则去模板文件夹中操作
  • jinjia2模板语法
    • {{}}
    • {%%}

自创Web框架之过度Django框架的更多相关文章

  1. python主流框架简介和Django框架的使用

    目录 一.手撸简易web框架 二.动静态网页 1. 静态网页 2. 动态网页 三.jinja2模板语法 1. jinja2的作用 四.python主流web框架 1. django 3. tornad ...

  2. DRF框架之使用Django框架完成后端接口(API)的定义

    学习DRF框架,首先我们就需要明白为什么要学习这个框架. 接下来我们就先用原生的Django框架来定义一个符合RESTful设计方法的接口(API). RESTful接口的需求如下: GET /boo ...

  3. Django框架01 / http协议、web框架本质

    Django框架01 / http协议.web框架本质 目录 Django框架01 / http协议.web框架本质 1.http协议 1.1 http协议简介 1.2 什么是http协议 1.3 H ...

  4. Pyhton-Web框架之【Django】

    一.什么是web框架 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演. 对于所有的 ...

  5. 第三百零三节,Django框架介绍——用pycharm创建Django项目

    Django框架介绍 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的软件设计模式,即模型M,视图V和控制器C.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内 ...

  6. 一 Django框架介绍——用pycharm创建Django项目

    Django框架介绍 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的软件设计模式,即模型M,视图V和控制器C.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内 ...

  7. Django框架——基础教程(总)

    1. Django简介 Python下有许多款不同的 Web 框架.Django是重量级选手中最有代表性的一位.许多成功的网站和APP都基于Django. Django是一个开放源代码的Web应用框架 ...

  8. Django 框架之前

    返回主目录:Django框架 内容目录: 一.Django框架之前的内容 1.1 web应用程序的架构 1.2 HTTP协议 1.3 纯手写简单web框架 一.Django框架之前d的内容 1.1 w ...

  9. WEB框架-Django框架学习-预备知识

    今日份整理,终于开始整个阶段学习的后期了,今日开始学习Django的框架,加油,你是最胖的! 1.web基础知识 1.1 web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是 ...

随机推荐

  1. vps上安装CobaltStrike服务端

    今天我在我的vps上安装CobaltStrike服务端,真的是踩坑无数,所以写这篇博客记录一下,防止后人再踩坑 安装Oracle JDK8 官方不建议使用OpenJdk,建议使用Oracle JDK的 ...

  2. Scala语言介绍一

    为什么学习scala语言 Scala是基于JVM的语言,与java语言类似,java语言是基于JVM的面向对象的语言,Scala也是基于JVM,同时支持面向对象和面向函数的编程语言.Spark底层的源 ...

  3. Cesium中级教程4 - 空间数据可视化(二)

    Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ Viewer中的Entity功能 让我们看看Viewer为操作e ...

  4. 一文读懂HarmonyOS服务卡片怎么换肤

    作者:zhenyu,华为软件开发工程师 关注HarmonyOS的小伙伴肯定对服务卡片已经很熟悉了.服务卡片(也简称为"卡片")是FA(FeatureAbility,元服务)的一种界 ...

  5. java抽象类案例

    1 package face_09; 2 /* 3 * 雇员示例: 4 * 需求:公司中程序员有姓名,工号,薪水,工作内容. 5 * 项目经理除了有姓名,工号,薪水,还有奖金,工作内容. 6 * 对给 ...

  6. 报错org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.mybatis.spring.SqlSessionFactoryBean]

    超级大坑 org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.mybati ...

  7. Android开发----WebView&Activity生命周期

    WebView webview是一个再应用中设置好位置和大小的浏览器,而且不会放置任何花哨的UI. 在大多数情况下,除非你调用了原生API,否则不必在webview中专门测试web应用. 首先为Web ...

  8. Redis 源码简洁剖析 03 - Dict Hash 基础

    Redis Hash 源码 Redis Hash 数据结构 Redis rehash 原理 为什么要 rehash? Redis dict 数据结构 Redis rehash 过程 什么时候触发 re ...

  9. 2.flink

    Flink 运行时的组件 作业管理器(JobManager) •控制一个应用程序执行的主进程,也就是说,每个应用程序都会被一个不同的JobManager 所控制执行. •JobManager 会先接收 ...

  10. JAVA中获取不同系统的换行符和获取系统路径路径分割符

    简介 JAVA具有多平台特征,一次开发,多平台运行,主要依据JVM,但是不同的操作系统中换行符和分割符不同,故需要根据不同的操作系统去获取不同的符号. JAVA代码 @Test public void ...