Python实现简单框架及三大框架对比
手撸web框架
简单的请求响应实现
要实现最简单的web框架,首先要对网络熟悉,首先HTTP协议是应用层的协议,只要我们给数据加上HTTP格式的响应报头,我们的数据就能基于socket进行实现了
import socket
sever = socket.socket()
sever.bind(('127.0.0.1',10000))
sever.listen(5)
while True:
conn,addr = sever.accept()
data = conn.recv(1024)
print(data)
#响应行
conn.send(b'HTTP/1.1 200 OK\n\r')
#响应头
conn.send(b'name:zx\r\n')
conn.send(b'age:23\r\n')
conn.send(b'sex:man\r\n')
#空行!区分头和响应体
conn.send(b'\r\n\r\n')
#响应体
conn.send(b'<h1>Hello world!</h1>')
#关闭连接
conn.close()
web框架的特点
我们熟悉的web框架其实都很类似,基本上也就三大块
路由选择-业务处理-ORM
路由选择
根据客户端的请求,跳转到响应的业务处理
业务处理
业务处理
数据库操作
网页模板渲染
ORM
数据库关系映射
代码实现
路由选择-urls.py
from views import *
urls = [
('/index',index),
('/login',login),
('/xxx',xxx),
('/get_time',get_time),
('/get_db',get_db)
]
业务处理-views.py
from orm import Teacher
def index(env):
return 'index'
def login(env):
return 'login'
def error(env):
return '404 error'
def xxx(env):
return 'xxx'
from datetime import datetime
def get_time(env):
current_time = datetime.now().strftime('%Y-%m-%d %X')
with open(r'C:\Users\Administrator\Desktop\01python\web\zx_web\time.html','r',encoding='utf-8') as f:
data = f.read()
#模板HTML渲染
data = data.replace('$$time$$',current_time)
return data
def get_db(env):
#ORM数据库操作
ret = Teacher.select(tid=1)[0]
print(ret)
return str(ret)
ORM
orm.py
from MySQL import MySQL
# 定义字段类
class Field(object):
def __init__(self, name, column_type, primary_key, default):
self.name = name
self.column_type = column_type
self.primary_key = primary_key
self.default = default
class StringField(Field):
def __init__(self,name,
column_type='varchar=(255)',
primary_key=False,
default=None):
super().__init__(name,column_type,primary_key,default)
class IntegerField(Field):
def __init__(self,
name,
column_type='int',
primary_key=False,
default=None):
super().__init__(name, column_type, primary_key, default)
class ModelMetaClass(type):
print("ModelMetaClass")
def __new__(cls,class_name,class_base,class_attrs):
print("ModelMetaClass_new")
#实例化对象的时候也会执行,我们要把这一次拦截掉
if class_name == 'Models':
#为了能让实例化顺利完成,返回一个空对象就行
return type.__new__(cls,class_name,class_base,class_attrs)
#获取表名
table_name = class_attrs.get('table_name',class_name)
#定义一个存主键的的变量
primary_key = None
#定义一个字典存储字段信息
mapping = {}
#name='tid',primary_key=True
#for来找到主键字段
for k,v in class_attrs.items():
#判断信息是否是字段
if isinstance(v,Field):
mapping[k] = v
#寻找主键
if v.primary_key:
if primary_key:
raise TypeError("主键只有一个")
primary_key=v.name
#将重复的键值对删除,因为已经放入了mapping
for k in mapping.keys():
class_attrs.pop(k)
if not primary_key:
raise TypeError("表必须要有一个主键")
class_attrs['table_name']=table_name
class_attrs['primary_key']=primary_key
class_attrs['mapping']=mapping
return type.__new__(cls,class_name,class_base,class_attrs)
class Models(dict,metaclass=ModelMetaClass):
print("Models")
def __init__(self,**kwargs):
print(f'Models_init')
super().__init__(self,**kwargs)
def __getattr__(self, item):
return self.get(item,"没有该值")
def __setattr__(self, key, value):
self[key]=value
#查找
@classmethod
def select(cls,**kwargs):
ms=MySQL()
#如果没有参数默认是查询全部的
if not kwargs:
sql='select * from %s'%cls.table_name
res=ms.select(sql)
else:
k = list(kwargs.keys())[0]
v = kwargs.get(k)
sql='select * from %s where %s=?'%(cls.table_name,k)
#防sql注入
sql=sql.replace('?','%s')
res=ms.select(sql,v)
if res:
return [cls(**i) for i in res]
#新增
def save(self):
ms=MySQL()
#存字段名
fields=[]
#存值
values=[]
args=[]
for k,v in self.mapping.items():
#主键自增,不用给他赋值
if not v.primary_key:
fields.append(v.name)
args.append("?")
values.append(getattr(self,v.name))
sql = "insert into %s(%s) values(%s)"%(self.table_name,",".join(fields),",".join((args)))
sql = sql.replace('?','%s')
ms.execute(sql,values)
def update(self):
ms = MySQL()
fields = []
valuse = []
pr = None
for k,v in self.mapping.items():
#获取主键值
if v.primary_key:
pr = getattr(self,v.name,v.default)
else:
fields.append(v.name+'=?')
valuse.append(getattr(self,v.name,v.default))
print(fields,valuse)
sql = 'update %s set %s where %s = %s'%(self.table_name,','.join(fields),self.primary_key,pr)
sql = sql.replace('?',"%s")
ms.execute(sql,valuse)
class Teacher(Models):
print("teacher")
table_name='teacher'
tid = IntegerField(name='tid',primary_key=True)
tname = StringField(name='tname')
if __name__ == '__main__':
# tea=Teacher(tname="haha")
tea2=Teacher(tname="haha",tid=5)
# print(Teacher.select(tid=1))
# Teacher.save(tea)
Teacher.update(tea2)
MYSQL.py
import pymysql
class MySQL:
#单例模式
__instance = None
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
def __init__(self):
self.mysql = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
database='orm_demo',
password='root',
charset='utf8',
autocommit=True
)
#获取游标
self.cursor = self.mysql.cursor(
pymysql.cursors.DictCursor
)
#查看
def select(self,sql,args=None):
print(sql,args)
#提交sql语句
self.cursor.execute(sql,args)
#获取查询的结果
res = self.cursor.fetchall()
return res
#提交
def execute(self,sql,args):
#提交语句可能会发生异常
print(sql,args)
try:
self.cursor.execute(sql,args)
except Exception as e:
print(e)
def close(self):
self.cursor.close()
self.mysql.close()
socket层
import socket
from urls import urls
from views import *
sever = socket.socket()
sever.bind(('127.0.0.1',10000))
sever.listen(5)
while True:
conn,addr = sever.accept()
#获取HTTP请求信息
data = conn.recv(1024)
data = data.decode('utf8')
print(data)
#用户请求的路由
choice = data.split(' ')[1]
#找到路由
func = None
for url in urls:
if choice == url[0]:
func = url[1]
break
if func:
res = func(data)
else:
res = '<h1>404 error</h1>'
#响应行
conn.send(b'HTTP/1.1 200 OK\n\r')
#响应头
conn.send(b'name:zx\r\n')
conn.send(b'age:23\r\n')
conn.send(b'sex:man')
#空行!区分头和响应体
conn.send(b'\r\n\r\n')
#响应体
conn.send(res.encode('utf8'))
#关闭连接
conn.close()
总结
其实并不是所有内容都要自己写,Python有很多的模块可以帮我们实现许多的功能
wsgiref模块:封装的一个socket服务,只需要关注数据发送和接收,不需要太多的关注HTTP协议的部分
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env,response):
"""
:param env: 请求相关的所有数据
:param response: 响应相关的所有数据
:return:
"""
response('200 OK',[])
# print(env)
current_path = env.get('PATH_INFO')
# 先定义一个变量名 用来存储后续匹配到的函数名
func = None
# for循环 匹配后缀
for url in urls:
if current_path == url[0]:
func = url[1] # 一旦匹配成功 就将匹配到的函数名赋值给func变量
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',8080,run)
# 实时监听该地址 只要有客户端来连接 统一交给run函数去处理
server.serve_forever() # 启动服务端
jinja2模块:模板渲染功能
模板语法(极其贴近python后端语法)
<p>{{ user }}</p>
<p>{{ user.name }}</p>
<p>{{ user['pwd'] }}</p>
<p>{{ user.get('hobby') }}</p>
{% for user_dict in user_list %}
<tr>
<td>{{ user_dict.id }}</td>
<td>{{ user_dict.name }}</td>
<td>{{ user_dict.pwd }}</td>
</tr>
{% endfor %}
Python实现简单框架及三大框架对比的更多相关文章
- python实现简单表单校验框架
# encoding=utf-8 from app.models import Student from flask import g import re from flask.ext.wtf imp ...
- java利用myeclipse自带三大框架搭建三大框架(Hibernate+Struts2+Spring)过程详解
搭建过程因人而异,我的搭建过程大致是这样的: 1.创建一个javaweb项目: 2.导入Spring框架,上图: 2.1: 2.2: 2.3: 3.导入struts2框架,上图: 3.1: 3.2: ...
- Django,Flask,Tornado三大框架对比,Python几种主流框架,13个Python web框架比较,2018年Python web五大主流框架
Django 与 Tornado 各自的优缺点Django优点: 大和全(重量级框架)自带orm,template,view 需要的功能也可以去找第三方的app注重高效开发全自动化的管理后台(只需要使 ...
- vue、react、angular三大框架对比 && 与jQuery的对比
前端当前最火的三大框架当属vue.react以及angular了. 但是在做项目的时候,我们怎么去选择呢? 这里做一个比较,希望大家可以有一个比较清晰的认识. vue与react vue和react ...
- python三大框架之一(flask介绍)
Flask , Django, Tornado 是python中常用的框架,也是python的三大框架.它们的区别是:Flask: 轻量级框架: Django:重量级框架: Tornado:性能最好 ...
- Python+selenium之简单介绍unittest单元测试框架
Python+selenium之简单介绍unittest单元测试框架 一.unittest简单介绍 unittest支持测试自动化,共享测试用例中的初始化和关闭退出代码,在unittest中最小单元是 ...
- vue、react、angular三大框架对比
前端的三大框架当属vue.react以及angular了,个人比较偏向react,它的社区比较繁荣,有很多丰富的组件 .angular的话感觉编译时间有点长,等待很恼火. vue与react vue和 ...
- python自动化测试(3)- 自动化框架及工具
python自动化测试(3) 自动化框架及工具 1 概述 手续的关于测试的方法论,都是建立在之前的文章里面提到的观点: 功能测试不建议做自动化 接口测试性价比最高 接口测试可以做自动化 后面所谈到 ...
- SSH三大框架笔面试总结
Java工程师(程序员)面题 Struts,Spring,Hibernate三大框架 1.Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建Sess ...
随机推荐
- 使用asp.net core 3.0 搭建智能小车2
上一篇中我们把基本的运行环境搭建完成了,这一篇中,我们实战通过树莓派B+连接HC-SR04超声波测距传感器,用c# GPIO控制传感器完成距离测定,并将距离显示在网页上. 1.HC-SR04接线 传感 ...
- 学习笔记04IIS
IIS机制:1.能监听端口,获取socket的客户端对象2.获取请求报文,将请求报文变成对象.3.处理请求报文,通过HttpApplication.ProcessRequest方法来处理HttpCon ...
- 第六篇 视觉slam中的优化问题梳理及雅克比推导
优化问题定义以及求解 通用定义 解决问题的开始一定是定义清楚问题.这里引用g2o的定义. \[ \begin{aligned} \mathbf{F}(\mathbf{x})&=\sum_{k\ ...
- [考试反思]1028csp-s模拟测试91:预估
这一轮是要闹哪样啊???前十都死活进不去??? 能不能不要到联赛前突然连续掉链子啊!!! 总算难得的切掉了T1.然后又一次把T2和T3的难度估反了 结果给T2剩下了30分钟,想到正解来不及打了. 然后 ...
- 大数据之路week01--自学之集合_2(列表迭代器 ListIterator)
列表迭代器: ListIterator listerator():List集合特有的迭代器 该迭代器继承了Iterator迭代器,所以,就可以直接使用hasNext()和next()方法 特有功能: ...
- Windows7下安装Linux双操作系统
本文链接:https://blog.csdn.net/zh175578809/article/details/78576193 最近正在学习Linux系统的常用操作命令,于是心血来潮,想自己安装一个L ...
- Linux下rpm仓库搭建
一.概念 1.rpm是什么?在帮助文档里我们可以看到,rpm的名字是rpm package manage 的缩写, 从名字上看就可以知道rpm就是一个包管理工具.简单说rpm包就是把一些程序编译成二进 ...
- mysql里面的时间获取(格式年月日)
1.当前日期 select DATE_SUB(curdate(),INTERVAL 0 DAY) ; 2.明天日期 select DATE_SUB(curdate(),INTERVAL -1 DAY) ...
- Python字符串类型判断错误
Python里面常用的字符串类型有str和unicode,如果要判断一个对象的类型,最好用basestring,否则可能会判断错误: str1 = "hello" str2 = u ...
- 使用 layUI做一些简单的表单验证
使用 layUI做一些简单的表单验证 <form method="post" class="layui-form" > <input name ...