3、自定义web框架及Django前戏

一、纯手撸web框架

版本①、超简易,只用了socket模块

# 只用了socket模块
# 做到传输html文件,以及自定义python的input输出到浏览器

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).decode("utf-8")
    # print(data)
    target_url = data.split(" ")[1]
    print(target_url)
    conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
    if target_url == "/index":
        # cont = input("请输入要传给浏览器的内容").strip()
        cont = "from /index"
        cont_send = bytes(cont, encoding="utf-8")
        conn.send(cont_send)
    elif target_url == "/func":
        with open("func.html","rb") as f:
            data = f.read()
        conn.send(data)
    else:
        conn.send(b"other")
-----------------------------------------------------------------------
存在的问题:
	1、代码过于冗余,每个人创建服务端都重新写一份socket模块写的原始代码
    	每次都要绑定一次bind,监听端口等等操作
    2、处理http数据繁杂
    
解决方法:
    找一个其他模块,看能不能不用写这么复杂的代码,提高开发效率
    # 下面尝试使用wsgiref模块

版本②、基于wsgiref模块撸web框架(python内置模块)

wsgi介绍

wsgi:
	Python Web Server Gateway Interface
    """
    是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。
    自从WSGI被开发出来以后,许多其它语言中也出现了类似接口。
    """

uwsgi
    """
    uwsgi是一种通信协议,不过跟WSGI分属两种东西,该协议下速度比较快。
    """

wsgiref

wsgiref模块
"""
	wsgiref则是官方给出的一个实现了WSGI标准用于演示用的简单Python内置库,
    它实现了一个简单的WSGI Server和WSGI Application(在simple_server模块中)
    要分为五个模块:simple_server, util, headers, handlers, validate。
"""

面条版代码1(耦合程度高,未整合)

from wsgiref.simple_server import make_server

def run(request,response):
    """
    :param request: 跟请求相关的数据
    :param response:跟相应相关的数据
    :return: 返回值就是要返回给前端浏览器的数据
    """
    response("200 OK",[])		# 为run方法return方法的空列表
    print(request)                          # request为一个字典,将每个信息都装成了K:V键值对。
    target_url = request.get("PATH_INFO")   # PATH_INFO 为用户输入的网站后缀名
    if target_url == "/index":
        return [b"from /index"]             # 返回给一个列表,里面是二进制的数据
    elif target_url == "/func":
        with open("func.html", "rb") as f:
            data = f.read()
        return [data]
    return [b"hello world"]		# 为response的空列表加值

if __name__ == '__main__':
    # 监听127.0.0.1:8080,一旦有请求发来,立马将第三个参数app加括号调用
    server = make_server("127.0.0.1",8080,app=run)  # 第三个参数app是上面的run方法

    # 启动服务端
    server.serve_forever()
-----------------------------------------------------------------------
存在的问题:
	1、用户输入的网站名以及返回的方法还需要一个个的添加
    2、实际工作中,返回的文件代码会有很多很多行,每次修改光查哪里错了,都要找很久

解决方法:
	做一个代码的整合,解耦合
    # 将

面条版代码2(解耦合,整合)

from wsgiref.simple_server import make_server

def index(request):
    return "index页面"

def login(request):
    return "login页面"

def error(request):
    return "error页面"

urls = [
    ("/index",index),
    ("/login",login),
]


def run(request,response):
    """
    :param request: 跟请求相关的数据
    :param response:跟相应相关的数据
    :return: 返回值就是要返回给前端浏览器的数据
    """
    response("200 OK",[])
    print(request)                          # request为一个字典,将每个信息都装成了K:V键值对。
    target_url = request.get("PATH_INFO")   # PATH_INFO 为用户输入的网站后缀名
    # 提前定义一个存储函数名的变量
    func = None
    for url_tuple in urls:
        if target_url == url_tuple[0]:
            func = url_tuple[1]
            break
    if func:
        res = func(request)
    else:
        res = error(request)
    return [res.encode("utf8")]

if __name__ == '__main__':
    server = make_server("127.0.0.1",8080,app=run)
    server.serve_forever()
-----------------------------------------------------------------------
存在的问题:
	1、面条版的代码,只有一个py文件,功能不清晰
    2、

解决方法:
	将每个功能分别做成py文件,解耦合程度更高一些

py代码整合为多文件

"""
以后新增功能,只需要先在 "views文件" 内写一个函数,
			然后在 "urls文件" 加一组对应关系即可

目录:
[项目名]--
        |--templates			# 文件夹,专门存放html文件
	    |--wsgi服务端代码启动.py
        |--urls.py				# 专门存放路径对应关系
        |--views.py				# 专门存放核心业务逻辑
"""
----------------------"wsgi服务端代码启动.py"----------------------
from wsgiref.simple_server import make_server
from urls import urls
from views import error

def run(request,response):
    response("200 OK",[])
    print(request)                          
    target_url = request.get("PATH_INFO")   
    func = None
    for url_tuple in urls:
        if target_url == url_tuple[0]:
            func = url_tuple[1]
            break
    if func:
        res = func(request)
    else:
        res = error(request)
    return [res.encode("utf8")]

if __name__ == '__main__':
    server = make_server("127.0.0.1",8080,app=run)
    server.serve_forever()

-----------------------------"urls.py"--------------------------
from views import *
urls = [
    ("/index",index),
    ("/login",login),
]

-----------------------------"views.py"--------------------------
def index(request):
    return "index页面"

def login(request):
    return "login页面"

def error(request):
    return "error页面"


----------------------------------------------------------------

二、动静态网页

动静态网页
	动态网页
    	数据不是直接写死在html页面上的 而是动态获取(后端)
    静态网页
    	数据是直接写死在页面上的
 
使用我们自己写的web框架 完成一个动态页面的返回

三、jinja2模块

该模块提供了"模板语法"
	支持后端给html页面传递数据并且支持后端语法
1、安装jinja2模块
	pip3 install jinja2

2、在上面的views.py下
from jinja2 import Template

user = {"username": "yly", "pwd": 123, "hobby": ["play python","play ball"]}
def get_dict(request):
    with open(r"Templates/get_dict.html", "r", encoding="utf8") as f:
        data = f.read()
    res = Template(data)
    temp = res.render({"user_dict": user})
    return temp
	
3、创建"Templates/get_dict.html" 文件
<!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>
</head>
<body>
    <h1>{{user_dict}}</h1>
	 <h1>{{user_dict}}</h1>
	 <h1>{{user_dict['username']}}</h1>
	 <h1>{{user_dict.get('pwd')}}</h1>
	 <h1>{{user_dict.hobby}}</h1>
<div>
    {% for key in user_dict%}
        <p>{{ key }}</p>
    {% endfor %}
</div>
</body>
</html>

4、打开web浏览器,输入"127.0.0.1:8080/get_dict",就显示字典内容


# 总结,jinja2的模板语法:
<h1>{{user_dict}}</h1>
<h1>{{user_dict['username']}}</h1>
<h1>{{user_dict.get('pwd')}}</h1>
<h1>{{user_dict.hobby}}</h1>
<div>
    {% for key in user_dict%}
        <p>{{ key }}</p>
    {% endfor %}
</div>

四、前端、web框架、数据库三者结合

需求:

查找后端数据库的数据,通过代码传到前端html页面展示出来

准备:

准备mysql数据库表:create database db_666;use db_666;create table user(id int primary key auto_increment,name varchar(32),pwd int);insert into user(name,pwd) values('yly',111),('zpx',222),('aaa',333),('bbb',444),('ccc',555);mysql> select * from user;+----+------+------+| id | name | pwd  |+----+------+------+|  1 | yly  |  111 ||  2 | zpx  |  222 ||  3 | aaa  |  333 ||  4 | bbb  |  444 ||  5 | ccc  |  555 |+----+------+------+5 rows in set (0.00 sec)

代码:

---------------------------------'urls.py'-------------------------------------from views import *urls = [    ("/index",index),    ("/login",login),    ("/get_dict",get_dict),    ("/get_user", get_user)]---------------------------------'views.py'-------------------------------------import pymysqldef get_user(request):    conn = pymysql.connect(        host='127.0.0.1',        port=3306,        user='root',        passwd='123',        database='db_666',        charset='utf8',        autocommit=True    )    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)    sql = "select * from user;"    cursor.execute(sql)    data_list = cursor.fetchall()        with open(r"Templates/get_user.html", "r", encoding="utf8") as f:        data = f.read()    # jinja2模块    res = Template(data)    tmp = res.render({"data_list": data_list})    return tmp

html文件

----------------------------"Templates/get_user.html"---------------------------<!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"></head><body><a href="/index">进入index界面</a><a href="/get_dict">进入get_dict界面</a>    <div class="container">        <div class="row">            <h1 class="text-center">用户数据</h1>            <div class="col-md-8 col-md-offset-2">                <table class="table table-hover table-striped">                    <thead>                        <tr>                            <th>编号</th>                            <th>姓名</th>                            <th>密码</th>                        </tr>                    </thead>                    <tbody>                        {% for user_dict in data_list %}                            <tr>                                <td>{{user_dict.id}}</td>                                <td>{{user_dict.name}}</td>                                <td>{{user_dict.pwd}}</td>                            </tr>                        {% endfor %}                    </tbody>                </table>            </div>        </div>    </div></body></html>

运行

1、运行开始python代码2、打开web,输入"127.0.0.1:8080/get_user"

五、python主流web框架

'''千万不要同时学习多个框架!!!'''django框架	大而全 内部自带的组件特别特别多 类似于航空母舰    有时候可能会过于"笨重"    flask框架	小而精 内部几乎没有什么自带的组件 全部依赖于第三方模块 类似于游骑兵    如果将flask所有的第三方模块集合到一起甚至可以盖过django    有时候可能会出现第三方模块无法兼容的情况tornado框架	异步非阻塞    """    同步异步    	同步:提交任务之后原地等待任务的返回结果 期间不做任何事    	异步:提交任务之后不原地等待任务返回结果 有结果会通过回调机制反馈    阻塞非阻塞    	阻塞:程序被剥夺了CPU执行权限    	非阻塞:运行态 就绪态    """    ------------------------------------------------A:socket部分B:路由匹配C:模板语法    django	A:不是自己写的 用的wsgiref模块    B:自己写的    C:自己写的flask	A:不是自己写的 werkzeug(依赖于wsgiref模块)    B:自己写的    C:不是自己写的 jinja2Tornado	A,B,C全部都是自己写的    知识储备:        fastapi框架        异步框架

六、Django框架正式介绍

1、安装及介绍

# 如何让你的计算机能够正常的启动Django项目1、计算机名称不能有中文2、一个pycharm窗口只开一个项目3、项目里面的文件也尽量不要出现中文4、python解释器尽量使用3.4~3.6之间的版本# django版本问题	django1.X    django2.X    django3.X    # django安装pip3 install django==1.11.11如果已经安装了其他版本 无需自己卸载直接重新装 会自动卸载安装新的# 验证django是否下载完毕(命令自动安装放在pip下的scripts文件夹内)	django-admin"""3.X支持异步(但是目前写的不好)1.X 2.X 3.X在使用上几乎没有太大差距针对django版本我们以1.11.11为学习对象"""

2、Django规划

3、django基本使用

----------------------------------"命令行"----------------------------------	1.创建django项目 	# 运行这行代码,会在当前路径生成项目文件夹    	django-admin startproject [项目名]    2.如何运行django项目    	切到项目目录下        	cd 项目名        python3 manage.py runserver			# 可能会报错 需要删除widgets.py152行逗号,python3.8解释器的错误            # 文件在Python3\lib\site-packages\django\contrib\admin\widgets.py    3.创建app    	python3 manage.py startapp app名字    """ 命令行创建不会自动创建templates文件夹 并且 [项目]/settings.py 配置文件中也不会配置需要自己创建文件夹并修改 "DIRS"vim settings.pyTEMPLATES = [    {        'BACKEND': 'django.template.backends.django.DjangoTemplates',        'DIRS': [],		# 需要加入:  os.path.join(BASE_DIR, 'templates')        				# 这个参数是固定的,所以pycharm创建,会自动添加        'APP_DIRS': True,        'OPTIONS': {            'context_processors': [                'django.template.context_processors.debug',                'django.template.context_processors.request',                'django.contrib.auth.context_processors.auth',                'django.contrib.messages.context_processors.messages',            ],        },    },]"""----------------------------------"pycharm启动"----------------------------------1、new project 选择左侧第二个django即可2、点击pycharm绿色小箭头即可启动	3、创建应用

pycharm使用django一些功能介绍

1、创建server以及配置启动ip及端口等等

2、pycharm便捷控制django,增加提示功能	例如:    	startapp

4、什么是app应用

"""django是一款专门用来开发app的web框架django框架就类似于是一所大学app就类似于大学里面各个学院	比如开发淘宝:		订单相关		用户相关		投诉相关		创建不同的app对应不同的功能		选课系统		学生功能		老师功能一个app就是一个独立的功能模块"""django相当于一所大学(空壳子)	app相当于大学里面的各个学院(功能主题)

注意事项

# 如何让你的计算机能够正常的启动Django项目1、计算机名称不能有中文2、一个pycharm窗口只开一个项目3、项目里面的文件也尽量不要出现中文4、python解释器尽量使用3.4~3.6之间的版本templates	放html文件

python小tips:

1、字符串与bytes类型的转换

str -> bytes	1、	        bytes1 = "yly".encode(encoding="utf8")    2、    	bytes2 = bytes("yly",encoding="utf8")bytes -> str	1、    	str1 = bytes1.decode(encoding="utf8")	2、    	str2 = str(bytes2,encoding="utf8")

2、类、对象也可以加括号调用

类加括号是实例化一个对象对象加括号是调用__call__方法如果直接print一个对象,则是调用__str__方法,获得他的return返回值(必须是字符串)

3、html请求地址

remote_addr 发起请求的ip
posted @ 2021-11-19 10:27  LionYie  阅读(44)  评论(0)    收藏  举报