学习Django框架之前所需要了解的知识点
目录
- 引入WEB框架
前端 后端 数据库
客户端发生 》》服务端接收 》》 处理 》》 返回
一: Web应用
1.Web应用程序什么?
Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件。
应用程序有两种模式C/S,B/S。
C/S是客户端/服务端程序,也就是说这类程序一般独立运行。
而B/S就是浏览器端/服务端应用程序,这类应用程序一般借助IE等浏览器来运行。
Web应用程序一般是B/S模式。Web应用程序首先是"应用程序",和标准的程序语言,如C,C++等编写出来的程序没有什么本质上的不同。然而Web应用程序又有自己独有的地方,就是它是基于Web的,而不是采用传统的方法运行的。换句话说,它是典型的浏览器/服务器架构的产物。
总结:
通过浏览器访问的应用都是Web应用!
2.软件开发架构
服务端需要具备的特征: 24小时对外提供服务
C/S: client: 客户端 server: 服务端
B/S browser: 浏览器 server: 服务端
# 本质上B/S架构也是C/S架构
3.Web应用程序的优点
- 网络应用程序不需要任何复杂的“展开”过程,你所需要的只是一个适用的浏览器;
- 网络应用程序通常耗费很少的用户硬盘空间,或者一点都不耗费;
- 它们不需要更新,因为所有新的特性都在服务器上执行,从而自动传达到用户端;
- 网络应用程序和服务器端的网络产品都很容易结合,如email功能和搜索功能;
- 因为它们在网络浏览器窗口中运行,所以大多数情况下它们是通过跨平台使用的 (例如Windows,Mac,Linux等等)
4.Web应用程序的缺点
- 网络应用程序强调浏览器的适用性。如果浏览器方没有提供特定的功能,或者弃用特定的平台或操作系统版本(导致不适用),就会影响大量用户;
- 网络应用依靠互联网远程服务器端的应用文件。因此,当连接出问题时,应用将不能正常使用。
- 许多网络应用程序不是开源的,只能依赖第三方提供的服务,因此不能针对用户定制化、个性化,而且大多数情况下用户不能离线使用,因而损失了很多灵活性;
- 它们完全依赖应用服务商的可及性。如果公司倒闭,服务器停止使用,用户也无法追索以前的资料。对比而看,即使软件制造商倒闭了,传统的安装软件也可以继续运行,尽管不能再更新或有其他用户服务;
- 相似地,提供方公司对软件和其功能有了更大的控制权。只要他们愿意就能为软件添加新特性,即使用户想等bugs先被解决再更新。跳过较差的软件版本也不可能了。公司可以强加不受欢迎的特性给用户,也可以随意减少带宽来削减开支。
- 公司理论上可以检索任何的用户行为。这有可能引起隐私安全问题。
5.B/S架构优点
浏览器/服务器架构(Browser/Server,简称B/S)能够很好地应用在广域网上,成为越来越多的企业的选择。浏览器/服务器架构相对于其他几种应用程序体系结构,有如下3方面的优点:
- 这种架构采用Internet上标准的通信协议(通常是TCP/IP协议)作为客户机同服务器通信的协议。这样可以使位于Internet任意位置的人都能够正常访问服务器。对于服务器来说,通过相应的Web服务和数据库服务可以对数据进行处理。对外采用标准的通信协议,以便共享数据。
- 在服务器上对数据进行处理,就处理的结果生成网页,以方便客户端直接下载。
- 在客户机上对数据的处理被进一步简化,将浏览器作为客户端的应用程序,以实现对数据的显示。不再需要为客户端单独编写和安装其他类型的应用程序。这样,在客户端只需要安装一套内置浏览器的操作系统,直接安装一套浏览器,就可以实现服务器上数据的访问。而浏览器是计算机的标准设备
6.Web框架本质
1.我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而且用户的浏览器就是一个socket客户端。
2.用户的浏览器一输入网址,会给服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来决定?
就如你网站是这样规定的,他网站按照他那样规定,这个互联网会能玩吗?
3.所以,必须有一个统一的规则,让大家发送消息、接收消息的时候有个格式依据,不能随便写。
4.这个规则就是HTTP协议,以后浏览器发送请求信息也好,服务器回复响应信息也罢,都要按照HTTP协议来。
5.HTTP协议主要规定了客户端和服务器之间的通信格式,那HTTP协议是怎么规定消息格式的呢?
让我们首先打印下我们在服务端接收到的消息是什么。
我们发现收发的消息需要按照一定的格式来,这里就需要了解一下HTTP协议了。
总结一下,本质上:浏览器是一个socket客户端,服务器是一个socket服务端
二:MVC和MTV模式
1.MVC设计模型
我们先对 MVC 设计模式进行介绍,它是 Web 设计模式的经典之作,MTV 模式也是在它的基础上衍生而来。
MVC 是 Model-View-Controller 的缩写,其中每个单词都有其不同的含义:
- Modle 代表数据存储层,是对数据表的定义和数据的增删改查;
- View 代表视图层,是系统前端显示部分,它负责显示什么和如何进行显示;
- Controller 代表控制层,负责根据从 View 层输入的指令来检索 Model 层的数据,并在该层编写代码产生结果并输出。
1. MVC:
M: model(跟数据打交道的)
V: View(视图, 页面)
C: controller(控制器,主要写逻辑的)
S:service (服务层)
MVC 设计模式的请求与响应过程描述如下:
- 用户通过浏览器向服务器发起 request 请求,Controller 层接受请求后,同时向 Model 层和 View 发送指令;
- Mole 层根据指令与数据库交互并选择相应业务数据,然后将数据发送给 Controller 层;
- View 层接收到 Controller 的指令后,加载用户请求的页面,并将此页面发送给 Controller 层;
- Controller 层接收到 Model 层和 View 层的数据后,将它们组织成响应格式发送给浏览器,浏览器通过解析后把页面展示出来。
2.扩展知识service层
当项目高并发比较大操作复杂的时候,抽象出一个S层,服务层公共的功能,以减轻高并发压力,低流量并发时,不需要使用S层。
service层的作用:
1. 封装通用的业务逻辑,操作。
如一些数据的检验,可以通用处理。
2. 与数据层的交互。
3. 其他请求:如远程服务获取数据,如第三方api等。
3.MTV设计模型
那么 Django 的 MTV 又是怎么回事呢?下面讲解 Django 的设计模式。
Django 借鉴了经典的MVC 模式,它将交互的过程分为3个层次,也就是MTV设计模式;
- Model:数据存储层,处理所有数据相关的业务,和数据库进行交互,并提供数据的增删改查;
- Template:模板层(也叫表现层)具体来处理页面的显示;
- View:业务逻辑层,处理具体的业务逻辑,它的作用是连通Model 层和 Template 。
2. MTV:
M: model(模型层:跟数据相关的)
T:template(模板:html页面)
V:view(主要写逻辑的)
同样我们也对 MTV 设计模式的请求与响应过程进行描述:
- 用户通过浏览器对服务器发起 request 请求,服务器接收请求后,通过 View 的业务逻辑层进行分析,同时向 Model 层和 Template 层发送指令;
- Mole 层与数据库进行交互,将数据返回给 View 层;
- Template 层接收到指令后,调用相应的模板,并返回给 View 层;
- View 层接收到模板与数据后,首先对模板进行渲染(即将相应的数据赋值给模板),然后组织成响应格式返回给浏览器,浏览器进行解析后并最终呈现给用户。
4.总结MTV与MVC
1.我们按照 MVC 的设计模式对 MTV 进行分析,MTV 设计模式中,用 View 层取代了 Controller 层的位置,用 Template 层取代了原来 View 层的位置。
2.初次接触 Django 的设计模式的人,可能会对 Template 层产生疑问,其实 Template 英文的含义就是“模板”的意思,你可以简单理解成,它是一个 HTML 页面 ,HTML 页面的渲染在视图层完成。
通过以上两种设计模式的比较, 我们可以得出 MTV 是 MVC 的一种细化,将原来 MVC 中的 V 层拿出来进行分离,视图的显示与如何显示交给 Template 层,而 View 层更专注于实现业务逻辑。其实在 Django 是有 Controller 层的,只不过它由框架本身来实现,所以我们不用关心它。Django 更关注于M、T 和 V。
三:网络协议之HTTP协议
1.网络协议
HTTP协议---------------数据传输是明文
HTTPS协议-------------数据传输是密文
websocket协议---------数据传输是密文
2.HTTP协议
超文本传输协议:规定了浏览器与服务器之间数据交互的格式
3.HTTP协议的四大特性
1.基于请求响应 -- 浏览器给服务端发起请求,服务端收到后做出回应
2.基于TCP、IP协议作用于应用层之上的协议
3.无状态 -- 不保存用户端的登录状态,见你千百遍我都当你如初见
4.无(短)连接 -- 一次请求响应后即断开连接
4.HTTP协议的数据传输格式
请求数据格式:
请求首行(请求方法...)
请求头(一大堆K:V键值对)
\r\n ---换行
请求体(并不是所有的请求方法都有 主要用来携带敏感性数据)
响应数据格式:
响应首行(响应状态码...)
响应头(一大堆k:v键值对)
\r\n ---换行
响应体(展示给用户的数据)
5.响应状态码
用简单的数字来表示一串中文意思
1XX:服务端已经接受到你的数据正在处理,你可以继续提交
2XX:200 OK >>>:请求成功
3XX:重定向 --原本想访问A,但是内部跳到B
4XX:403当前请求不符合条件 404请求资源不存在
5XX:服务器内部错误
eg:除了上述统一的响应状态码之外,公司还可以自定义自己的状态码
6.post与get请求方法
1.get请求
朝别人索要数据
2.post请求
朝别人提交数据
>>>上述两种请求都可以携带额外的参数<<<
get请求携带数据的方式:
url?username=jason&hobby=mn
post请求携带数据的方式:
数据是放在请求体里面的
7.请求数据格式示例:
# 请求首行--\r\n是换行符
b'GET / HTTP/1.1\r\n
# 请求头(都是一大堆k:v键值对)
Host: 127.0.0.1:8080\r\n
Connection: keep-alive\r\n
Cache-Control: max-age=0\r\n
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"\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 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 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/signedexchange;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,en;q=0.8\r\n
\r\n'
# 请求体(下面是空的:因为发出的是get请求 get请求不需要请求体)
四:基于SOCKET写一个web应用(纯手撸web框架)
1.类型转换(了解)
采用此类方式实现类型转换可以不需要用encode 和 decode
1.只需要认识str和bytes就行了
data = b'hello world'
2.转字符串
data1 = str(data,encoding='utf8')
print(data1)
3.转bytes类型
data2 = bytes(data1,encoding='utf8')
print(data2)
2.如何做到后缀的不同返回不同的内容
如何做到后缀的不同返回不同的内容
拿到用户输入的url后缀 做判断
import socket
server = socket.socket() # TCP 三次握手 四次挥手
server.bind(('127.0.0.1',8080)) # IP协议
server.listen(5) # 半连接池
while True:
conn, addr = server.accept()
data = conn.recv(1024)
print(data) # 二进制数据
# 直接忽略favicon.ico
conn.send(b'HTTP/1.1 200 OK\r\n\r\nhello web')
conn.close()
3.实现用户输入不同的后缀,返回不同的内容
实现用户输入不同的后缀,返回不同的内容
while True:
conn, addr = server.accept()
data = conn.recv(1024)
# print(data) # 二进制数据
data = data.decode('utf-8') # 解码 转成字符串
# TCP是流式协议
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
# 获取字符串中特定的内容 正则 如果字符串有规律也可以考虑用切割
current_path = data.split(' ')[1]
print(current_path) # 用户输入后缀
# 判断用户输入的后缀
if current_path == '/index':
conn.send(b'index hello world')
elif current_path == '/login':
conn.send(b'login')
else:
# 直接忽略favicon.ico
conn.send(b'hello web')
conn.close()
4.实现用户输入不同的后缀,返回html文件内容
实现用户输入不同的后缀,返回html文件内容
while True:
conn, addr = server.accept()
data = conn.recv(1024)
# print(data) # 二进制数据
data = data.decode('utf-8') # 解码 转成字符串
# TCP是流式协议
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
# 获取字符串中特定的内容 正则 如果字符串有规律也可以考虑用切割
current_path = data.split(' ')[1]
print(current_path) # 用户输入后缀
# 判断用户输入的后缀
if current_path == '/index':
conn.send(b'index hello world')
elif current_path == '/login':
conn.send(b'login')
elif current_path == '/html':
# 实现返回HTML文件内容
with open(r'myhtml.html','rb') as f:
conn.send(f.read())
else:
# 直接忽略favicon.ico
conn.send(b'hello web')
conn.close()
5.纯手撸 不足之处
纯手撸 不足之处
1.代码重复(服务端代码所有人都要重复写)
2.手动处理http格式的数据 并且只能拿到url后缀 其他数据获取繁琐(数据格式一样处理的代码其实也大致一样 重复写)
3.并发的问题
6.问题:
服务端代码重复
手动处理http数据格式过于频繁
五:基于Wsgiref模块(解决上述两个问题)
1.做到后缀的不同返回不同的内容
做到后缀的不同返回不同的内容
拿到用户输入的url后缀 做判断
2.实现用户输入后缀不同返回不同的内容
from wsgiref.simple_server import make_server
def run(env,response):
"""
:param env: 请求相关的所有数据
:param response: 响应相关的所有数据
:return: 返回给浏览器的数据
"""
print(env) # 大字典 wsgiref模块帮你处理好http格式的数据 让你更好的操作
# 从env中取 拿到当前用户输入的后缀
current_path = env.get('PATH_INFO')
# 判断用户输入的后缀
if current_path == '/index':
return [b'index']
elif current_path == '/login':
return [b'login']
# 定制404页面
return [b'404 error']
if __name__ == '__main__':
# 接收mack_server 的返回值
server = make_server('127.0.0.1',8080,run)
"""
会实时监听127.0.0.1:8080地址 只要有客户端来了
都会交给run函数处理(加括号触发run函数的运行)
"""
server.serve_forever() # 启动服务端
六:借助于wsgiref模块
urls.py 路由与视图函数对应关系
views.py 视图函数(后端业务逻辑)
templates文件夹 专门用来存储html文件
路由:
路由就是url的后缀
视图函数:
函数处理的结果,一般都要经过浏览器,所以叫视图函数
按照功能的不同拆分之后 后续添加功能只需要在urls.py书写对应关系然后取views.py书写业务逻辑即可
1.wsgiref.py 启动核心文件
wsgiref.py 启动核心文件
from wsgiref.simple_server import make_server
# 导入对应关系文件
from urls import urls
# 导入业务逻辑文件
from views import *
def run(env,response):
"""
:param env: 请求相关的所有数据
:param response: 响应相关的所有数据
:return: 返回给浏览器的数据
"""
# print(env) #大字典 wsgiref模块帮你处理好http格式的数据 让你更好的操作
response('200 OK',[]) # 响应首行 响应头
# 从env中取 拿到当前用户输入的后缀
current_path = env.get('PATH_INFO')
# 定义一个变量 存储匹配到的函数名
func = None
for url in urls: # url (),()
# 判断用户输入后缀是否等于列表内的某个元组的第一个元素 访问后面的功能
if current_path == url[0]:
# 将url对应的函数名赋值给func
func = url[1]
break # 匹配到一个之后 应该立刻结束当前for循环
# 判断func是否有值
if func:
# 有值情况执行func()
res = func(env) # 将env传给函数
else:
res = error(env) # 将env传给函数
# 统一编码
return [res.encode('utf-8')]
if __name__ == '__main__':
# 接收mack_server 的返回值
server = make_server('127.0.0.1',8080,run)
"""
会实时监听127.0.0.1:8080地址 只要有客户端来了
都会交给run函数处理(加括号触发run函数的运行)
"""
server.serve_forever() # 启动服务端
2.urls.py 对应关系
urls.py 对应关系
# 导入业务逻辑文件
from views import *
# url与函数的对应关系
urls = [
('/index',index),
('/login',login),
('/xxx',xxx)
]
3.views.py 业务逻辑 (函数)
views.py 业务逻辑 (函数)
def index(env):
return 'index'
def login(env):
return 'login'
def error(env):
return '404 error'
def xxx(env):
# 打开templates文件夹内的html文件
with open(r'templates/myhtml.html', 'r',encoding='utf-8') as f:
return f.read()
七:动静态网页
1.静态网页与动态网页
静态网页
页面上的数据是直接写死的 万年不变
动态网页
数据是实时获取的
eg:
1.后端获取当前时间展示到html页面上
2.数据是从数据库中获取的展示到html页面上
2.动态网页制作
3.views.py 业务逻辑
def get_time(env):
# 获取当前时间
current_time = datetime.datetime.now().strftime('%Y-%m-%d %X')
# 将后端获取到的数据"传递"给html文件
# 1.先打开html文件
with open(r'templates/mytime.html', 'r',encoding='utf-8') as f:
data = f.read()
# data就是一堆字符串 replace替换 将字符串替换成当前时间
data = data.replace('sdsdsdsdsd',current_time) # 在后端将html页面处理好之后再返回给前端
return data
将一个字典传递给html文件 并且可以在文件上方便快捷的操作字典数据
from jinja2 import Template
def get_dict(env):
user_dic = {'username':'jason','age':18,'hobby':'read'}
with open(r'templates/get_dict.html','r',encoding='utf-8') as f:
data = f.read()
tmp = Template(data) # 使用template 就可以给html文件传值了
# 给get_dict.html传递了一个值 页面上通过变量名user就能够拿到user_dict
res = tmp.render(user=user_dic)
return res
后端获取数据库中数据展示到前端页面
八:模版语法之Jinja2模块
1.命令行安装模板语法
pip3 install jinja2
"""模版语法是在后端起作用的"""
2.模版语法(非常贴近python语法)
{{ user }}
{{ user.get('username')}}
{{ user.age }}
{{ user['hobby'] }}
3.后端获取数据库中数据展示到前端页面
- 后端
# 导入pymysql
import pymysql
def get_user(env):
# 去数据库中获取数据 传递给html页面 借助于模板语法 发送给浏览器。
# 创建连接
conn = pymysql.connect( # 赋值给conn连接对象
host = '127.0.0.1', # 本地回环地址ip
port = 3306, # 端口
user = 'root', # 用户名
password = '123', # 密码
db='day01', # 连接数据库名称
charset = 'utf8', # 编码
autocommit = True # 自动提交
)
# 生成一个游标对象(相当于cmd打开MySQL中的 mysql>)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 让数据自动生成字典
# 定义sql语句
sql = 'select * from userinfo'
# 执行sql语句
affect_rows = cursor.execute(sql)
# [{},{},{}] 拿到的列表套字典
data_list = cursor.fetchall()
# 将获取到的数据传递给html文件
with open(r'templates/get_data.html','r',encoding='utf-8') as f:
data = f.read()
# 使用jinja2 就可以给html文件传值
tmp = Template(data)
# 给get_dict.html传递了一个值 页面上通过变量名user_list就能够拿到data_list
res = tmp.render(user_list=data_list)
return res
if __name__ == '__main__':
get_user(111)
4.前端
<!--表格展示 列表套字典的数据 模板语法支持for循环-->
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">用户数据</h1>
<table class="table table-hover table-striped">
<thead>
<tr>
<th>ID</th>
<th>username</th>
<th>password</th>
<th>hobby</th>
</tr>
</thead>
<tbody>
<!--[{},{},{},{}] 下面有一个列表套字典的用户数据 每拿一个字典 渲染一个tr-->
<!--模块语法操作-->
{% for user_dict in user_list %}
<tr>
<td>{{ user_dict.id}}</td>
<td>{{ user_dict.name}}</td>
<td>{{ user_dict.password}}</td>
<td>{{ user_dict.hobby}}</td>
{% endfor%}
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!--{{ user_list }}-->数据库
5.数据库
后端连接pymysql 使用可视化软件
6.结果
九:总结
1.纯手撸web框架
- 1.socket代码需要我们自己写
- 2.http格式的数据自己处理(只能拿到用户输入的路由)
2.基于wsgiref模块
- 1.封装了socket代码
- 2.处理了http数据格式
web服务网关接口
- 1.请求来的时候解析http格式的数据,封装成了大字典
- 2.响应走的时候把数据打包成符合http格式,在返回给浏览器
3.根据功能的不同拆分成不同的文件夹
urls.py 路由与视图函数对应关系:主要是匹配浏览器请求的视图页面并交由对应视图函数处理
views.py 视图函数:得到浏览器的页面请求及浏览器携带的请求数据,进行html页面提取、数据处理、模板渲染并返回
templates 模板文件夹:放有所有前端html页面文件夹
- 1.第一步添加路由与视图函数的对应关系
- 2.去views中书写功能代码
- 3.如果需要使用到html则去模板文件夹中操作
4.jinja2模板语法
{{···}}
{%···%}
十:自定义简易版本web框架请求流程图
wsgiref模块
1.请求来的时候解析http格式的数据 封装成大字典
2.响应走的时候给数据打包成符合http格式 再返回给浏览器