学习Django框架之前所需要了解的知识点

  • 引入WEB框架
前端			后端			数据库

客户端发生 》》服务端接收 》》 处理 》》 返回

image

一: 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 (服务层)

image

MVC 设计模式的请求与响应过程描述如下:
  • 用户通过浏览器向服务器发起 request 请求,Controller 层接受请求后,同时向 Model 层和 View 发送指令;
  • Mole 层根据指令与数据库交互并选择相应业务数据,然后将数据发送给 Controller 层;
  • View 层接收到 Controller 的指令后,加载用户请求的页面,并将此页面发送给 Controller 层;
  • Controller 层接收到 Model 层和 View 层的数据后,将它们组织成响应格式发送给浏览器,浏览器通过解析后把页面展示出来。
2.扩展知识service层
  当项目高并发比较大操作复杂的时候,抽象出一个S层,服务层公共的功能,以减轻高并发压力,低流量并发时,不需要使用S层。   

service层的作用:
1. 封装通用的业务逻辑,操作。
如一些数据的检验,可以通用处理。
2. 与数据层的交互。
3. 其他请求:如远程服务获取数据,如第三方api等。 

img

3.MTV设计模型
那么 Django 的 MTV 又是怎么回事呢?下面讲解 Django 的设计模式。
Django 借鉴了经典的MVC 模式,它将交互的过程分为3个层次,也就是MTV设计模式;
  • Model:数据存储层,处理所有数据相关的业务,和数据库进行交互,并提供数据的增删改查;
  • Template:模板层(也叫表现层)具体来处理页面的显示;
  • View:业务逻辑层,处理具体的业务逻辑,它的作用是连通Model 层和 Template 。
2. MTV:
    M: model(模型层:跟数据相关的)
    T:template(模板:html页面)  
    V:view(主要写逻辑的)

image

同样我们也对 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()

image

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()

image

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()

image

5.纯手撸 不足之处
纯手撸 不足之处
	1.代码重复(服务端代码所有人都要重复写)
  2.手动处理http格式的数据 并且只能拿到url后缀 其他数据获取繁琐(数据格式一样处理的代码其实也大致一样 重复写)
  3.并发的问题
6.问题:
服务端代码重复
手动处理http数据格式过于频繁

五:基于Wsgiref模块(解决上述两个问题)

1.做到后缀的不同返回不同的内容
做到后缀的不同返回不同的内容
拿到用户输入的url后缀 做判断 

image

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()  # 启动服务端

image

六:借助于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

image

将一个字典传递给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'] }}

image

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)

image

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 使用可视化软件

image

6.结果

image

九:总结

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格式 再返回给浏览器

image

posted @ 2022-02-23 15:14  AlexEvans  阅读(285)  评论(0编辑  收藏  举报