1 |0 自己动手实现一个简易版本的web框架
在了解python的三大web框架之前,我们先自己动手实现一个。
备注:
这部分重在掌握实现思路,代码不是重点
代码中也有许多细节并未考虑,重在实现思路
1 |1 手撸一个web服务端
我们一般是使用浏览器当做客户端,然后基于HTTP协议自己写服务端代码 作为服务端
先自行去回顾一下HTTP协议 这一块儿的知识
import socket
server = socket.socket()
然后右键运行,在浏览器访问 127.0.0.1:8080 即可看到响应数据
关于启动服务器与页面请求(在我处理的时候,页面网络请求会经常处于 pending状态,不是很清楚原因,一般这个情况下,直接重启一下服务器即可)
1 |2 根据请求 url 做不同的响应处理
上面的代码已经实现了基本请求响应,那如何根据不同的请求作出不同的响应呢?
我们输入不同的url,看看服务器端会返回什么
分析请求
8080/index
GET /index HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs
浏览器访问 http://127.0.0.1:8080/home
GET /home HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs
原来请求首行的 GET 后面跟的就是请求我们想要信息(/index 首页、/home 家)
这些信息也是我们接收到的(data = conn.recv(2048) print(str(data, encoding='utf-8'))),那可不可以取出来,根据值的不同作不同处理呢?
处理请求,获取 url
'''GET /home HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs'''
print(data.split('\n')[0].split(' ')[1])
依据上述切割规则,我们来对不同的请求作出不同的响应
import socket
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
conn, addr = server.accept()
data = conn.recv(2048).decode('utf-8')
data = data.split('\n')[0].split(' ')[1]
print(data)
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
if data == '/index':
response = '<h3>这里是 index...</h3>'.encode('GBK')
elif data == '/home':
response = '<h3>这里是 home...</h3>'.encode('GBK')
else:
response = '<h3>404 NOT FOUND...\n找不到您要找的资源...</h3>'.encode('GBK')
conn.send(response)
conn.close()
页面成功显示不同的信息
http://127.0.0.1:8080/index
http://127.0.0.1:8080/home
http://127.0.0.1:8080/de2332f
404页面 也应该算作设计网站的一部分,可以给人不一样的感觉
2 |0 基于wsgiref模块实现服务端
前面处理 scoket 和 http 的那堆代码通常是不变的,且与业务逻辑没什么关系,如果每个项目都要写一遍,那岂不是很麻烦?那封装成模块嘛~
不过这个操作已经有人帮我们做了,并且封装的更加强大,就是 wsgiref 模块
2 |1 用wsgiref 模块的做的两件事
在请求来的时候,自动解析 HTTP 数据,并打包成一个字典,便于对请求发过来的数据进行操作
发响应之前,自动帮忙把数据打包成符合 HTTP 协议的格式(响应数据格式,不需要再手动写 conn.send(b'HTTP/1.1 200 OK\r\n\r\n') 了),返回给服务端
# 导模块
def run(env, response):
"""
先不管这里的 env 和 response 什么个情况
env:是请求相关的数据,wsgiref帮我们把请求包装成了一个大字典,方便取值
response:是响应相关的数据
"""
response('200 OK', [])
print(env)
current_path = env.get('PATH_INFO')
print(current_path)
if current_path == '/index':
return ['hello, there is index...'.encode('utf-8')]
elif current_path == '/login':
return ['hello, there is login...'.encode('utf-8')]
else:
return ['sorry... that pages you want is not found...'.encode('utf-8')]
if __name__ == '__main__':
伏笔
拆分服务端代码
服务端代码、路由配置、视图函数,照目前的写法全都冗在一块儿,后期功能扩展时,这个文件会变得很长,不方便维护,所以选择把他拆分开来
就是将服务端代码拆分成如下三部分:
server.py 放服务端代码
urls.py 放路由与视图函数对应关系
views.py 放视图函数/类(处理业务逻辑)
views.py
(env):
return 'index'
def login(env):
return 'login'
urls.py
import *
urls = [
('/index', index),
('/login', login),
]
server.py
# 导模块
from urls import urls
2 |2 支持新的请求地址(添加新页面/新功能)
经过上面的拆分后,后续想要支持其他 url,只需要在 urls.py 中添加一条对应关系,在 views.py 中把该函数实现,重启服务器即可访问
以支持 http://127.0.0.1:8080/new_url 访问为例
urls.py
import *
urls = [
('/index', index),
('/login', login),
('/new_url', new_url),
]
views.py
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
重启服务器 ,打开浏览器即可访问 http://127.0.0.1:8080/new_url
扩展性高了很多,且逻辑更清晰了,更不容易弄错(框架的好处提现,也是为什么脱离了框架不会写的原因,这块代码写的太少,不常用到,没了框架又写不出来)
3 |0 动态静态网页--拆分模板文件
前面写了那么多,都只是一直在返回纯文本信息,而我们一般请求页面返回的都是浏览器渲染好的华丽的页面,那要怎么放回华丽的页面呢?
页面嘛,就是 HTML + CSS + JS 渲染出来的,所以我们也可以把 HTML文件当成数据放在响应体里直接返回回去
新建一个功能的步骤 还是复习一下
在 urls.py 里面加一条路由与视图函数的对应关系
在 views.py 里面加上那个视图函数,并写好内部逻辑代码
重启服务器,浏览器打开页面访问
3 |1 返回静态页面--案例
这里咱们就接着上面的 new_url 写,用他来返回 一个网页
新建一个 templates 文件夹,专门用来放 HTML 文件
templates/new_url.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>New URL</h1>
<h5>Wellcome!</h5>
</body>
</html>
views.py
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
重启服务器,使用浏览器访问
上面提到了静态页面,那什么是静态页面?什么又是动态页面呢?
静态网页: 纯html网页,数据是写死的,所有同url的请求拿到的数据都是一样的
动态网页: 后端数据拼接,数据不是写死的,是动态拼接的,比如:
后端实时获取当前时间“传递”(塞)给前端页面展示
后端从数据库获取数据“传递”给前端页面展示
4 |0 实现返回时间--插值思路(动态页面)
要怎么在 html 里插入时间呢?
往 html 里的插入?那替换好像也可以达到效果啊?
html_data = f.read() ? 好像 html 被读出出来了,而且还是二进制的,二进制可以 decode 变成字符串,字符串有 replace方法可以替换字符串,那我随便在网页里写点内容,然后替换成时间?
先把基础歩鄹做好
templates/get_time.html 编写展示页面
put_times_here 用来做占位符,一会儿给他替换成时间
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>北京时间:</h1>
<h1>put_time_here</h1>
</body>
</html>
urls.py 路由与视图函数对应关系
import *
urls = [
('/index', index),
('/login', login),
('/new_url', new_url),
('/get_time', get_time),
]
views.py 实现视图函数
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
重启服务器并打开浏览器访问 http://127.0.0.1:8080/get_time
关键思路: 相当于占位符,字符串替换,后期把前端要替换的字符的格式统一规定下,方便阅读与统一处理,这其实也就是目前的模版语法的雏形
我们只需要把处理好的字符串(HTML格式的)返回给浏览器,待浏览器渲染即可有页面效果
5 |0 利用 jinja2 模块实现动态页面
jinja2模块有着一套 模板语法,可以帮我更方便地在 html 写代码(就想写后台代码一样),让前端也能够使用后端的一些语法操作后端传入的数据
5 |1 安装 jinja2
jinja2 并不是 python 解释器自带的,所以需要我们自己安装
由于 flask 框架是依赖于 jinja2 的,所下载 flask 框架也会自带把 jinja2 模块装上
命令行执行,pip3 install jinja2 或图形化操作安装 (参考 Django 的安装方法)
5 |2 初步使用
这里只是知道有模板语法这么一个东西可以让我们很方便的往 html 写一些变量一样的东西,并不会讲 jinja2 的语法,后续会有的
案例--展示字典信息
urls.py
import *
urls = [
('/index', index),
('/login', login),
('/new_url', new_url),
('/get_time', get_time),
('/show_dic', show_dic),
]
views.py
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
templates/show_dic.html 写页面
jinja2 给字典扩展了点语法支持({{ dic.username }})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Nice to meet you~ i'm {{ dic.username }} , and i'm {{ dic.age }} years old.</h1>
<p>username: {{ dic['username']}}</p>
<p>age: {{ dic.get('age')}}</p>
</body>
</html>
重启服务器并打开浏览器访问 http://127.0.0.1:8080/show_dic
为什么说动态?
如果你改变了字典里的值,那么请求这个页面,显示的数据也会跟着改变(注意这个字典一般都是其他地方获取过来的)
模板语法(贴近python语法): 前端也能够使用后端的一些语法操作后端传入的数据
{{data.password}}
进阶案例--渲染数据库数据到页面
思路
pymsql 从数据库取数据(指定成 列表套字典 的格式(DictCursor))
后台 python 代码处理数据
交由 jinja2 模块语法渲染到 html 页面上
数据条数不定怎么办?
有多少条记录就显示多少条呗...循环?
表格格式先写好,然后循环渲染数据到标签上(特定语法表示循环)
数据准备
创建数据库 django_test_db ,然后执行如下 SQL 命令
/*
Navicat MySQL Data Transfer
Source Server : localhost-E
Source Server Type : MySQL
Source Server Version : 50645
Source Host : localhost:3306
Source Schema : django_test_db
Target Server Type : MySQL
Target Server Version : 50645
File Encoding : 65001
Date: 15/09/2019 00:41:09
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
配路由与视图函数
urls.py
import *
urls = [
('/index', index),
('/login', login),
('/new_url', new_url),
('/get_time', get_time),
('/show_dic', show_dic),
('/get_users', get_users),
]
views.py
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
op_mysql.py 如果你的配置不一样要自己改过来
import pymysql
def get_cursor():
server = pymysql.connect(
templates/get_users.html 用户信息展示页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
用浏览器访问 http://127.0.0.1:8080/get_users,重启服务器,在切回浏览器即可看到页面效果
6 |0 推导流程与小总结
1.纯手撸web框架
1.手动书写socket代码
2.手动处理http数据
2.基于wsgiref模块帮助我们处理scoket以及http数据(顶掉上面的歩鄹)
wsgiref模块
1.请求来的时候 解析http数据帮你打包成一个字典传输给你 便于你操作各项数据
2.响应走的时候 自动帮你把数据再打包成符合http协议格式的样子 再返回给前端
3.封装路由与视图函数对应关系 以及视图函数文件 网站用到的所有的html文件全部放在了templates文件夹下
1.urls.py 路由与视图函数对应关系
2.views.py 视图函数 (视图函数不单单指函数 也可以是类)
3.templates 模板文件夹
4.基于jinja2实现模板的渲染
模板的渲染
后端生成好数据 通过某种方式传递给前端页面使用(前端页面可以基于模板语法更加快捷简便使用后端传过来的数据)
6 |1 流程图
6 |2 小扩展
在不知道是要 encode 还是 decode 的时候,可以用一下方法
二进制数据对应的肯定是 decode 解码 成字符串呀
字符串对应的肯定是 encode 编码成二进制数据呀
数据类型转换技巧(处理编码) (数据 + encoding)
# 转成 bytes 类型
bytes(data, encoding='utf-8')
7 |0 python三大Web主流框架分析对比
7 |1 Django
大而全,自带的功能特别特别多,就类似于航空母舰
缺点: 有时过于笨重(小项目很多用不到)
7 |2 Flask
短小精悍,自带的功能特别少,全都是依赖于第三方组件(模块)
第三方组件特别多 --> 如果把所有的第三方组件加起来,完全可以盖过django
缺点: 比较受限于第三方的开发者(可能有bug等)
7 |3 Tornado
天生的异步非阻塞框架,速度特别快,能够抗住高并发
可以开发游戏服务器(但开发游戏,还是 C 和C++用的多,执行效率更快)
7 |4 手撸三大部分在框架中的情况对比
前面的手撸推导过程,整个框架过程大致可以分为以下三部分
A:socket处理请求的接收与响应的发送
B:路由与视图函数
C:模板语法给动态页面渲染数据
Django
A:用的别人 的 wsgiref 模块 B:自带路由与视图函数文件 C:自带一套模板语法
Flask
A:用的别人 的werkzeug 模块(基于 wsgiref 封装的) B:自带路由与视图函数文件 C:用的别人 的jinja2
Tornado
A,B,C全都有自己的实现
8 |0 Django的下载安装基本使用
参见我的另一篇博客:Django-下载安装-配置-创建django项目-三板斧简单使用
__EOF__
作 者:Suwanbin 出 处:https://www.cnblogs.com/suwanbin/p/11520959.html 关于博主:希望我的博客对你能有所帮助,如果内容有什么错误,欢迎评论指出哦,或者直接私信 我 版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本 。 声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【 推荐】 一下。您的鼓励是博主的最大动力!
posted @ 收藏
返回顶部
发表评论
昵称:
订阅评论
[Ctrl+Enter快捷键提交]
MENU
Django-手撸简易web框架-实现动态网页-wsgiref初识-jinja2初识-python主流web框架对比-00
Posted by Suwanbin on 2019-09-15 01:23
DJANGO框架实现原理
【等到黑夜翻面之后????会是新的白昼】
ღゝ◡╹)ノ♡
Copyright © 2019 suwanbin
v1.1.4
1 |0 自己动手实现一个简易版本的web框架
在了解python的三大web框架之前,我们先自己动手实现一个。
备注:
这部分重在掌握实现思路,代码不是重点
代码中也有许多细节并未考虑,重在实现思路
1 |1 手撸一个web服务端
我们一般是使用浏览器当做客户端,然后基于HTTP协议自己写服务端代码 作为服务端
先自行去回顾一下HTTP协议 这一块儿的知识
import socket
server = socket.socket()
然后右键运行,在浏览器访问 127.0.0.1:8080 即可看到响应数据
关于启动服务器与页面请求(在我处理的时候,页面网络请求会经常处于 pending状态,不是很清楚原因,一般这个情况下,直接重启一下服务器即可)
1 |2 根据请求 url 做不同的响应处理
上面的代码已经实现了基本请求响应,那如何根据不同的请求作出不同的响应呢?
我们输入不同的url,看看服务器端会返回什么
分析请求
8080/index
GET /index HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs
浏览器访问 http://127.0.0.1:8080/home
GET /home HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs
原来请求首行的 GET 后面跟的就是请求我们想要信息(/index 首页、/home 家)
这些信息也是我们接收到的(data = conn.recv(2048) print(str(data, encoding='utf-8'))),那可不可以取出来,根据值的不同作不同处理呢?
处理请求,获取 url
'''GET /home HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs'''
print(data.split('\n')[0].split(' ')[1])
依据上述切割规则,我们来对不同的请求作出不同的响应
import socket
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
conn, addr = server.accept()
data = conn.recv(2048).decode('utf-8')
data = data.split('\n')[0].split(' ')[1]
print(data)
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
if data == '/index':
response = '<h3>这里是 index...</h3>'.encode('GBK')
elif data == '/home':
response = '<h3>这里是 home...</h3>'.encode('GBK')
else:
response = '<h3>404 NOT FOUND...\n找不到您要找的资源...</h3>'.encode('GBK')
conn.send(response)
conn.close()
页面成功显示不同的信息
http://127.0.0.1:8080/index
http://127.0.0.1:8080/home
http://127.0.0.1:8080/de2332f
404页面 也应该算作设计网站的一部分,可以给人不一样的感觉
2 |0 基于wsgiref模块实现服务端
前面处理 scoket 和 http 的那堆代码通常是不变的,且与业务逻辑没什么关系,如果每个项目都要写一遍,那岂不是很麻烦?那封装成模块嘛~
不过这个操作已经有人帮我们做了,并且封装的更加强大,就是 wsgiref 模块
2 |1 用wsgiref 模块的做的两件事
在请求来的时候,自动解析 HTTP 数据,并打包成一个字典,便于对请求发过来的数据进行操作
发响应之前,自动帮忙把数据打包成符合 HTTP 协议的格式(响应数据格式,不需要再手动写 conn.send(b'HTTP/1.1 200 OK\r\n\r\n') 了),返回给服务端
# 导模块
def run(env, response):
"""
先不管这里的 env 和 response 什么个情况
env:是请求相关的数据,wsgiref帮我们把请求包装成了一个大字典,方便取值
response:是响应相关的数据
"""
response('200 OK', [])
print(env)
current_path = env.get('PATH_INFO')
print(current_path)
if current_path == '/index':
return ['hello, there is index...'.encode('utf-8')]
elif current_path == '/login':
return ['hello, there is login...'.encode('utf-8')]
else:
return ['sorry... that pages you want is not found...'.encode('utf-8')]
if __name__ == '__main__':
伏笔
拆分服务端代码
服务端代码、路由配置、视图函数,照目前的写法全都冗在一块儿,后期功能扩展时,这个文件会变得很长,不方便维护,所以选择把他拆分开来
就是将服务端代码拆分成如下三部分:
server.py 放服务端代码
urls.py 放路由与视图函数对应关系
views.py 放视图函数/类(处理业务逻辑)
views.py
(env):
return 'index'
def login(env):
return 'login'
urls.py
import *
urls = [
('/index', index),
('/login', login),
]
server.py
# 导模块
from urls import urls
2 |2 支持新的请求地址(添加新页面/新功能)
经过上面的拆分后,后续想要支持其他 url,只需要在 urls.py 中添加一条对应关系,在 views.py 中把该函数实现,重启服务器即可访问
以支持 http://127.0.0.1:8080/new_url 访问为例
urls.py
import *
urls = [
('/index', index),
('/login', login),
('/new_url', new_url),
]
views.py
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
重启服务器 ,打开浏览器即可访问 http://127.0.0.1:8080/new_url
扩展性高了很多,且逻辑更清晰了,更不容易弄错(框架的好处提现,也是为什么脱离了框架不会写的原因,这块代码写的太少,不常用到,没了框架又写不出来)
3 |0 动态静态网页--拆分模板文件
前面写了那么多,都只是一直在返回纯文本信息,而我们一般请求页面返回的都是浏览器渲染好的华丽的页面,那要怎么放回华丽的页面呢?
页面嘛,就是 HTML + CSS + JS 渲染出来的,所以我们也可以把 HTML文件当成数据放在响应体里直接返回回去
新建一个功能的步骤 还是复习一下
在 urls.py 里面加一条路由与视图函数的对应关系
在 views.py 里面加上那个视图函数,并写好内部逻辑代码
重启服务器,浏览器打开页面访问
3 |1 返回静态页面--案例
这里咱们就接着上面的 new_url 写,用他来返回 一个网页
新建一个 templates 文件夹,专门用来放 HTML 文件
templates/new_url.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>New URL</h1>
<h5>Wellcome!</h5>
</body>
</html>
views.py
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
重启服务器,使用浏览器访问
上面提到了静态页面,那什么是静态页面?什么又是动态页面呢?
静态网页: 纯html网页,数据是写死的,所有同url的请求拿到的数据都是一样的
动态网页: 后端数据拼接,数据不是写死的,是动态拼接的,比如:
后端实时获取当前时间“传递”(塞)给前端页面展示
后端从数据库获取数据“传递”给前端页面展示
4 |0 实现返回时间--插值思路(动态页面)
要怎么在 html 里插入时间呢?
往 html 里的插入?那替换好像也可以达到效果啊?
html_data = f.read() ? 好像 html 被读出出来了,而且还是二进制的,二进制可以 decode 变成字符串,字符串有 replace方法可以替换字符串,那我随便在网页里写点内容,然后替换成时间?
先把基础歩鄹做好
templates/get_time.html 编写展示页面
put_times_here 用来做占位符,一会儿给他替换成时间
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>北京时间:</h1>
<h1>put_time_here</h1>
</body>
</html>
urls.py 路由与视图函数对应关系
import *
urls = [
('/index', index),
('/login', login),
('/new_url', new_url),
('/get_time', get_time),
]
views.py 实现视图函数
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
重启服务器并打开浏览器访问 http://127.0.0.1:8080/get_time
关键思路: 相当于占位符,字符串替换,后期把前端要替换的字符的格式统一规定下,方便阅读与统一处理,这其实也就是目前的模版语法的雏形
我们只需要把处理好的字符串(HTML格式的)返回给浏览器,待浏览器渲染即可有页面效果
5 |0 利用 jinja2 模块实现动态页面
jinja2模块有着一套 模板语法,可以帮我更方便地在 html 写代码(就想写后台代码一样),让前端也能够使用后端的一些语法操作后端传入的数据
5 |1 安装 jinja2
jinja2 并不是 python 解释器自带的,所以需要我们自己安装
由于 flask 框架是依赖于 jinja2 的,所下载 flask 框架也会自带把 jinja2 模块装上
命令行执行,pip3 install jinja2 或图形化操作安装 (参考 Django 的安装方法)
5 |2 初步使用
这里只是知道有模板语法这么一个东西可以让我们很方便的往 html 写一些变量一样的东西,并不会讲 jinja2 的语法,后续会有的
案例--展示字典信息
urls.py
import *
urls = [
('/index', index),
('/login', login),
('/new_url', new_url),
('/get_time', get_time),
('/show_dic', show_dic),
]
views.py
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
templates/show_dic.html 写页面
jinja2 给字典扩展了点语法支持({{ dic.username }})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Nice to meet you~ i'm {{ dic.username }} , and i'm {{ dic.age }} years old.</h1>
<p>username: {{ dic['username']}}</p>
<p>age: {{ dic.get('age')}}</p>
</body>
</html>
重启服务器并打开浏览器访问 http://127.0.0.1:8080/show_dic
为什么说动态?
如果你改变了字典里的值,那么请求这个页面,显示的数据也会跟着改变(注意这个字典一般都是其他地方获取过来的)
模板语法(贴近python语法): 前端也能够使用后端的一些语法操作后端传入的数据
{{data.password}}
进阶案例--渲染数据库数据到页面
思路
pymsql 从数据库取数据(指定成 列表套字典 的格式(DictCursor))
后台 python 代码处理数据
交由 jinja2 模块语法渲染到 html 页面上
数据条数不定怎么办?
有多少条记录就显示多少条呗...循环?
表格格式先写好,然后循环渲染数据到标签上(特定语法表示循环)
数据准备
创建数据库 django_test_db ,然后执行如下 SQL 命令
/*
Navicat MySQL Data Transfer
Source Server : localhost-E
Source Server Type : MySQL
Source Server Version : 50645
Source Host : localhost:3306
Source Schema : django_test_db
Target Server Type : MySQL
Target Server Version : 50645
File Encoding : 65001
Date: 15/09/2019 00:41:09
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
配路由与视图函数
urls.py
import *
urls = [
('/index', index),
('/login', login),
('/new_url', new_url),
('/get_time', get_time),
('/show_dic', show_dic),
('/get_users', get_users),
]
views.py
(env):
return 'index'
def login(env):
return 'login'
def new_url(env):
op_mysql.py 如果你的配置不一样要自己改过来
import pymysql
def get_cursor():
server = pymysql.connect(
templates/get_users.html 用户信息展示页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
用浏览器访问 http://127.0.0.1:8080/get_users,重启服务器,在切回浏览器即可看到页面效果
6 |0 推导流程与小总结
1.纯手撸web框架
1.手动书写socket代码
2.手动处理http数据
2.基于wsgiref模块帮助我们处理scoket以及http数据(顶掉上面的歩鄹)
wsgiref模块
1.请求来的时候 解析http数据帮你打包成一个字典传输给你 便于你操作各项数据
2.响应走的时候 自动帮你把数据再打包成符合http协议格式的样子 再返回给前端
3.封装路由与视图函数对应关系 以及视图函数文件 网站用到的所有的html文件全部放在了templates文件夹下
1.urls.py 路由与视图函数对应关系
2.views.py 视图函数 (视图函数不单单指函数 也可以是类)
3.templates 模板文件夹
4.基于jinja2实现模板的渲染
模板的渲染
后端生成好数据 通过某种方式传递给前端页面使用(前端页面可以基于模板语法更加快捷简便使用后端传过来的数据)
6 |1 流程图
6 |2 小扩展
在不知道是要 encode 还是 decode 的时候,可以用一下方法
二进制数据对应的肯定是 decode 解码 成字符串呀
字符串对应的肯定是 encode 编码成二进制数据呀
数据类型转换技巧(处理编码) (数据 + encoding)
# 转成 bytes 类型
bytes(data, encoding='utf-8')
7 |0 python三大Web主流框架分析对比
7 |1 Django
大而全,自带的功能特别特别多,就类似于航空母舰
缺点: 有时过于笨重(小项目很多用不到)
7 |2 Flask
短小精悍,自带的功能特别少,全都是依赖于第三方组件(模块)
第三方组件特别多 --> 如果把所有的第三方组件加起来,完全可以盖过django
缺点: 比较受限于第三方的开发者(可能有bug等)
7 |3 Tornado
天生的异步非阻塞框架,速度特别快,能够抗住高并发
可以开发游戏服务器(但开发游戏,还是 C 和C++用的多,执行效率更快)
7 |4 手撸三大部分在框架中的情况对比
前面的手撸推导过程,整个框架过程大致可以分为以下三部分
A:socket处理请求的接收与响应的发送
B:路由与视图函数
C:模板语法给动态页面渲染数据
Django
A:用的别人 的 wsgiref 模块 B:自带路由与视图函数文件 C:自带一套模板语法
Flask
A:用的别人 的werkzeug 模块(基于 wsgiref 封装的) B:自带路由与视图函数文件 C:用的别人 的jinja2
Tornado
A,B,C全都有自己的实现
8 |0 Django的下载安装基本使用
参见我的另一篇博客:Django-下载安装-配置-创建django项目-三板斧简单使用
__EOF__
作 者:Suwanbin 出 处:https://www.cnblogs.com/suwanbin/p/11520959.html 关于博主:希望我的博客对你能有所帮助,如果内容有什么错误,欢迎评论指出哦,或者直接私信 我 版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本 。 声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【 推荐】 一下。您的鼓励是博主的最大动力!