首页 > 其他分享 >第一章:手写简易的web框架,了解Django的原理

第一章:手写简易的web框架,了解Django的原理

时间:2022-12-13 00:12:42浏览次数:58  
标签:web get index server user env 手写 Django data

手写一个简单的web框架

纯手撸简易版的web框架

import socket


# 括号后面什么都不加默认tcp协议
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)  # 请求协议
    """
    b'GET / HTTP/1.1\r\n
    Host: 127.0.0.1:8080\r\n
    Connection: keep-alive\r\n
    Cache-Control: max-age=0\r\n
    sec-ch-ua: "Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"\r\n
    sec-ch-ua-mobile: ?0\r\n
    sec-ch-ua-platform: "Windows"\r\n
    Upgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n
    Sec-Fetch-Site: none\r\n
    Sec-Fetch-Mode: navigate\r\n
    Sec-Fetch-User: ?1\r\n
    Sec-Fetch-Dest: document\r\n
    Accept-Encoding: gzip, deflate, br\r\n
    Accept-Language: zh-CN,zh;q=0.9\r\n\r\n'
    """

    # 把请求从二进制改为字符的形式,以便获取请求内容
    data = data.decode('utf-8')
    # tcp是流式协议,这样写就不用每发一个响应就写一个
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    # 以空格为切割符,把请求切成一个列表,这样用户访问的后缀就是索引为1的字符串。例如:http://127.0.0.1:8080/index,index就是用户访问的后缀
    current_path = data.split(' ')[1]
    # print(current_path)  # '/index'
    # 当用户的后缀为index时,返回一个HTML页面
    if current_path == '/index':
        with open(r'一个页面.html', 'rb') as f:
            conn.send(f.read())
    elif current_path == '/liu':
        conn.send(b'liujieshishazi')
    else:
        conn.send(b'hello web')
    # 关闭链接
    conn.close()

手写框架的不足之处

1、代码重复

2、手动处理请求数据繁琐

3、并发问题

基于wsgiref模块进行接收数据和响应数据

导入wsgiref模块:

from wsgiref.simple_server import make_server

from wsgiref.simple_server import make_server


def run(env, response):
    """
    :param env: 请求相关的所有数据,返回一个字典,wsgiref模块帮你处理好http格式的数据,封装成了字典让你更加方便的操作数据
    :param response: 响应相关的所有数据
    :return: 返回给浏览器的数据
    """
    response('200 OK', [])  # 响应首行 响应头
    # 从字典中取出数据,key为PATH_INFO的value是用户传的后缀
    current_path = env.get('PATH_INFO')
    if current_path == '/index':
        return [b'index']
    elif current_path == '/liu':
        return [b'liuhousheng']
    return [b'404']


if __name__ == '__main__':
    """
    实时监听127.0.0.1:8080地址,只要有客户端来了
    都会交给run函数处理(加括号触发run函数的运行)
    """
    server = make_server('127.0.0.1', 8080, run)
    # 启动服务器
    server.serve_forever()


wsgiref模块代码优化与封装

"""
运行文件			  用wsgiref模块写出主干
urls.py				路由与视图函数对应关系
views.py			视图函数(后端业务逻辑)
templates文件夹	  专门用来储存HTML文件
"""
# 按照功能的不同拆分之后,后续功能只需要在urls.py书写对应的关系后再去views.py书写业务逻辑即可
运行文件代码
from wsgiref.simple_server import make_server
# 导入文件urls
from urls import urls
# 导入views
from views import *


def run(env, response):
    """
    :param env: 请求相关的所有数据,返回一个字典,wsgiref模块帮你处理好http格式的数据,封装成了字典让你更加方便的操作数据
    :param response: 响应相关的所有数据
    :return: 返回给浏览器的数据
    """
    response('200 OK', [])  # 响应首行 响应头
    # 从字典中取出数据,key为PATH_INFO的value是用户传的后缀
    current_path = env.get('PATH_INFO')
    # 定义一个变量为空
    func = None
    # for循环urls列表得到一个个元组
    for url in urls:
        # 取出元组中索引为0的元素,判断是否有获取到的路由
        if current_path == url[0]:
            # 判断成功把元组中索引为1的元素赋值给func变量
            func = url[1]
            # 判断成功立刻结束for循环
            break
    # 判断func是否为空
    if func:
        # func不为空,加括号运行,并把env传过去,以便再进行取值操作
        res = func(env)
    else:
        # func为空,运行404的函数
        res = error(env)
    # 把返回的值编码成二进制的形式传给浏览器
    return [res.encode('utf-8')]


if __name__ == '__main__':
    """
    实时监听127.0.0.1:8080地址,只要有客户端来了
    都会交给run函数处理(加括号触发run函数的运行)
    """
    server = make_server('127.0.0.1', 8080, run)
    # 启动服务器
    server.serve_forever()

urls文件代码
from views import *

urls = [
    ('/index', index),
    ('/login', login),
    ('/error', error)
]

views文件代码
def index(env):
    with open(r'templates/index.html', 'r', encoding='utf-8') as f:
        return f.read()


def login(env):
    with open(r'templates/login.html', 'r', encoding='utf-8') as f:
        return f.read()


def error(env):
    with open(r'templates/error.html', 'r', encoding='utf-8') as f:
        return f.read()

模板语法之jinja2模块

给前端传一个字典数据

# 写在views文件中
# 并且在urls文件中写入路由对应关系:('/get_dic', get_dic)
# 导入jinja2模块
from jinja2 import Template
def get_dic(env):
    # 创建一个字典
    user_dic = {'username': 'liujie', 'password': 123, 'age': 18, 'hobby': 'read'}
    # 打开文件,读模式
    with open(r'templates/get_dic.html', 'r', encoding='utf-8') as f:
        data = f.read()
        
    # 给get_dic.html传递字典user_dic,用变量名user接收,在前端页面就可以使用user访问字典内容
    tmp = Template(data)
    res = tmp.render(user=user_dic)
    
    # 把HTML文件返回浏览器渲染
    return res

HTML输出字典内容的几种方法

<body>
    <h1>这是一个标签</h1>
    // 固定语法,通过双大括号从后端取值
    {{ user }}
    // jinja2与Python语法接近
    // 从字典通过key取值的三种方法
    <div>用户姓名:{{ user.get('username') }}</div>
    <div>用户密码:{{ user.password }}</div>
    <div>用户年龄:{{ user['age'] }}</div>
</body>

结合mysql数据库给前端提交数据

# 写在views文件中
# 并且在urls文件中写入路由对应关系:('/get_user', get_user)
import pymysql
from jinja2 import Template
def get_user(env):
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='123',
        database='get_user',  # 一定要指定库
        charset='utf8',  # 编码千万不要加-,会报错
        # 是否自动提交
        autocommit=True
    )  # 链接数据库
    # 产生一个游标对象(就是用来帮你执行命令的)
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # SQL语句
    sql = 'select * from user'
    # 返回值是你当前SQL语句所影响的行数
    affect_rows = cursor.execute(sql)
    # 拿到所有的数据
    data_list = cursor.fetchall()
    with open(r'templates/get_user.html', 'r', encoding='utf-8') as f:
        data = f.read()

    tmp = Template(data)
    res = tmp.render(user_dic=data_list)
    return res

模板语法的for循环

<thead>
    <tr>
        <th>id</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>爱好</th>
    </tr>
</thead>
<tbody>
    {% for user in user_dic %}
    <tr>
        <td>{{ user.id }}</td>
        <td>{{ user.name }}</td>
        <td>{{ user.age }}</td>
        <td>{{ user.hobby }}</td>
    </tr>
    {% endfor %}
</tbody>

标签:web,get,index,server,user,env,手写,Django,data
From: https://www.cnblogs.com/liuhousheng/p/16977502.html

相关文章

  • 可视化界面之数据增删改查、django请求生命周期图、django路由层、反向解析
    可视化界面之数据增删改查django请求生命周期流程图django路由层反向解析可视化界面之数据增删改查建表建表、加索引可以体现程序员的工作经验。建表......
  • Django框架三
    Django框架(三)Django请求生命周期流程图扩展知识点缓存数据库 浏览器向后端发送请求,在经过Django中间件之后,会先从缓存数据库寻找数据,如果没有则向后端数据库要数......
  • nginx https作网关配置webapi路由规则
    为何有这篇文章?因为我有多个小程序,分别调用不同的api站点,服务器只能安装一个https单域名证书。 1、原webapi接口部署完毕,接口地址比如​​http://www.zyiz.net/api/getarti......
  • webkit nw.js 默认 每个窗口都最大化打开
    一、前景nw.js每打开一个窗口都是默认大小,需要每个弹出窗口都是最大化窗口。二、方案根据官网给出的参数:1、编写一个待置入js,放到目录js/下,每一个打开的页面窗......
  • django无名分组和反向解析
    django请求生命周期流程图当客户端浏览器访问django后端时django框架中发生了哪些事情呢?客户端请求服务端时将客户端请求的各种数据和信息进行整理。应用程序则负责具体......
  • Django-路由层、反向解析
    1.Django请求生命周期流程图1.路由层、视图层、模板层、模型层、组件、BBS项目2.django路由层1.路由匹配:'''当我们输入一个地址时,接口后面的/不用输入,也可以自动跳......
  • Web开发人员必备的20款超赞的jQuery插件
    导语:jQuery的易扩展性吸引了来自全球的开发者来共同编写jQuery插件。jQuery插件不仅能够增强网站的可用性,有效地改善用户体验,还可以大大减少开发时间。现在的jQuery插件很多......
  • asp.net web mvc form表单提交
    1、指定action<formaction="/control/action1"method="post"><inputtype="submit"value="保存"/></form>publicstringaction1(FormCollectionform){}//......
  • django_应用及分布式路由
    一、应用的定义1、应用在Django中是一个独立的业务模块,可以包含自己的路由、视图、模板、模型。例如如下图所示,一个资讯类网站中会有不同的模块,如果所有的模......
  • Django之数据增删改查、Django请求生命周期流程图、Django路由层(路由匹配、转换器、正
    今日内容详细可视化界面之数据增删改查针对数据对象主键字段的获取可以使用更加方便的obj.pk获取在模型类中定义__str__方法可以在数据对象被执行打印操作的时候方......