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三大主流web框架
Django:
        大而全 自带的功能特别特别多 类似于航空母舰
        有时候过于笨重
Flask
    小而精 自带的功能特别特别少 类似于游骑兵
    第三方的模块特别特别多,如果将flask第三方模块全部加起来 完全可以超过django

    比较依赖于第三方模块
Tornado
    异步非阻塞
    牛逼到可以开发游戏服务器
A:socket部分
B:路由与视图函数对应关系
C:模板语法

Django:
    A用的别人的  wsgiref
    B自己写的
    C自己写的
Flask
    A用的别人的  werkzeug(基于wsgiref)
    B自己写的
    C用的别人的  jinja2
Tornado
    三者全是自己写的

原文地址:https://www.cnblogs.com/zx125/p/11704617.html

时间: 2024-10-14 00:46:43

Python实现简单框架及三大框架对比的相关文章

python实现简单表单校验框架

# encoding=utf-8 from app.models import Student from flask import g import re from flask.ext.wtf import Form from wtforms import StringField, RadioField, PasswordField, TextAreaField, BooleanField, DateField, ValidationError, IntegerField from wtform

java利用myeclipse自带三大框架搭建三大框架(Hibernate+Struts2+Spring)过程详解

搭建过程因人而异,我的搭建过程大致是这样的: 1.创建一个javaweb项目: 2.导入Spring框架,上图: 2.1: 2.2: 2.3: 3.导入struts2框架,上图: 3.1: 3.2: next: 3.3: 4.导入Hibernate框架,说明:由于hibernate属于持久层,和数据库密切相关,所以需要我们提前出创建好数据库对应视图,然后再开始下面的操做.上图: 4.1: 4.2: 4.3: 4.4: 4.5: 4.6: 4.7:利用数据库相关表和hibernate的orm生成实

前端如何入门面对传统的html,css,js,三大框架react,vue,angular?

前端入门需要学习 A基础知识部分 1.html一些新的标签,html不仅仅包括div,span 2.css3,一些新的语法,布局,例如flex弹性布局,less,sass都是啥 3.DOM树结构,盒模型(margin,padding,border)不同浏览器层次不一样,尤其IE 4.数据交互插件,ajax,fetch,axios等等,要求自己能封装出一个ajax类,供自己用 B前端环境,软件 nodejs,npm 1.了解node,npm是干什么的,为什么前端要用这些 2.自己搜索npm官网,c

三大框架(SSH)关于URL转发乱码问题(最简单暴力的一种解决办法)

这两天在整合三大框架时遇上Struts2的URL转发乱码问题,搞了很久也上网查了很多资料,写了过滤器,改过配置,全部都没用.只能用最简单暴力的一种,手动转换乱码.因为编辑器一开始默认的编码是ISO-8859-1,所以要将ISO-8859-1转换成utf-8. 一般乱码问题,先检验数据库的编码是否对应,一般安装数据库的时候设定了默认编码,如果没有设定为utf-8,添加中文时可能会出现乱码---只能修改配置或重装数据库(这不是本博文的重点).检验数据库后,再检验页面编码是否一致,若还不能解决乱码问题

vue、react、angular三大框架对比

前端当前最火的三大框架当属vue.react以及angular了. 但是在做项目的时候,我们怎么去选择呢?  这里做一个比较,希望大家可以有一个比较清晰的认识. vue与react vue和react是当前最火的两个前端框架,vue的发展很快,但是目前来说,react的生态系统会更强大,世界上使用这个框架的人也很多. 另外,react是facebook官方维护的, 而vue是尤雨溪本人维护的. 并且在其他周边库,如react的react-rouer和redux,是react社区在维护的. 而vu

java 三大框架面试题

1.Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory3.打开Session 4.创建事务Transation 5.持久化操作 6.提交事务 7.关闭Session 8.关闭SesstionFactory 为什么要用: 1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码. 2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现.他很大程度的简化DAO层的编码工作

Struts,Spring,Hibernate三大框架 面试题

Struts,Spring,Hibernate三大框架 1.Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3.打开Session 4.创建事务Transation 5.持久化操作 6.提交事务 7.关闭Session 8.关闭SesstionFactory 为什么要用: 1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码. 2. Hibernate是一个基于JDBC的主流持久化框架,

前端三大框架Angular &amp; React &amp; Vue

前端三大框架: Angular[Google]:一套框架,多种平台移动端 & 桌面端.学会用Angular构建应用,然后把这些代码和能力复用在多种多种不同平台的应用上 —— Web.移动 Web.移动应用.原生应用和桌面原生应用. React[Facebook Open Source]用于用户界面构建的JAVASCRIPT库. 初步认识:react可以使构建交互UI的过程变得简单.对于你的应用里面的每个状态视图,当数据变化的时候,React都会及时并且正确有效率地进行对其更新.这种陈述式视图,将

JAVA三大框架SSH的各自作用

一.Spring Spring是一个解决了许多在J2EE开发中常见的问题的强大框架. Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯.Spring的架构基础是基于使用JavaBean属性的Inversion of Control容器.然而,这仅仅是完整图景中的一部分:Spring在使用IoC容器作为构建完关注所有架构层的完整解决方案方面是独一无二的. Spring提供了唯一的数据访问抽象,包括简单和有效率的JDBC框架,极大的改进了效率并且减少了可能的错