Web框架的本质

我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端,这样我们就可以自己实现Web框架

软件开发架构:

c/s架构 客户端与服务端
b/s结构 浏览器与服务端

半成品自定义Web架构

import socket
​
server = socket.socket()  # 不传参数默认TCP协议通信
# 绑定 IP PORT
server.bind(('127.0.0.1', 8080))  # 服务端:1.固定的ip+port,2.24小时不间断服务,3.支持高并发
# 半连接池
server.listen(5)  # 降低效率,保证服务端硬件的安全性
while True:
    conn, addr = server.accept()  # 等待客户端连接 
    data = conn.recv(1024)  # 接收客户端请求信息
    conn.send(b'hello Django')  # 向客户端响应信息,但响应失败,客户端无法接收,因为没有遵循HTTP协议

 

Web服务本质上都是这十几行代码基础上扩展出来的.
用户在浏览器输入网址:
浏览器发请求(get/post) <--> HTTP协议 <--> 服务端响应请求
HTTP协议规定了客户端与服务端消息的传世格式,那么我们就看看是怎样规定显式格式的,我们在服务端打印出接收到的信息是什么

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)
    print(data)  # 打印客户端请求数据
    conn.send(b'hello Django')

# 打印出来的请求数据
''' b'GET / HTTP/1.1\r\n Host: 127.0.0.1:8080\r\n Connection: keep-alive\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\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 ' '''

 

我们发现收发的消息需要按照一定的格式来,这里就需要了解一下HTTP协议了

HTTP协议对收发消息的格式要求

每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。 HTTP响应的Header中有一个 `Content-Type`表明响应的内容格式。如 `text/html`表示HTML网页。

wsgiref 与 Django框架初识

 

wsgiref 与 Django框架初识

 

处女版自定义Web框架

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)
    conn.send(b'HTTP/1.1 200 OK\r\n\r\nhello Django')
    conn.colse()

 

以上就是web 框架的本质。

接下来就就是完善我们的自定义web框架

根据不同的路径返回不同的内容

如何让我们的Web服务根据用户请求的URL不同而返回不同的内容呢?
我们发现,用户输入不同的url在服务端接收的请求是不一样的,区别在与
b'GET /index HTTP/1.1\r\nHost: 127.0.0.1:8080\r\n.....
里面多了/index,也就是用户输入的url后缀,那么我们就可以通过切分拿到/index后缀,在进行判断返回相应的响应就可以
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)  
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # TCP 流式协议特性
    data = data.decode('utf-8')
    current_path = data.split('\r\n')[0].split(' ')[1]  # 拿到url后缀
    if current_path == '/index':  # 判断后缀,响应响应的功能
        conn.send(b'index')
    elif current_path == '/text':
        with open(r'1html.html', 'rb') as f:
            conn.send(f.read())
    else:
        conn.send(b'hello Django')
    conn.close()

 

wsgiref

from wsgiref.simple_server import make_server
# wsgiref 将socket封装好了
​
​
def run(env, response):
    '''
    env 是请求相关的数据
    response 是响应相关的数据
    '''
    print(env)  # 收到的是一个字典,里面的 键 PATN_INFO 对应的值就是客户端url的请求后缀
    response('200 OK', [])
    return [b'hello Django']
​
​
if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)
    # 实时监测127.0.0.1:8080地址,一旦有客户端连接,会自动加括号调用run方法
    server.serve_forever()  # 启动服务端

 

wsgiref 与 Django框架初识

根据不同的路径返回不同的内容--函数进阶版

from wsgiref.simple_server import make_server
# wsgiref 将socket封装好了
​
​
def index(env):
    return 'index'def login(env):
    return 'login'def errors(env):
    return '404 error'
​
urls = [
    ('/index', index),
    ('/login', login),
]
​
def run(env, response):
​
    response('200 OK', [])
    current_path = env.get('PATH_INFO')# 拿到的是URL后缀
# 定义一个存储函数的标志位
    func = None
    for url in urls:
        # 判断当前请求的url是否在元组内
        if url[0] == current_path:
            # 若在,赋值给func
            func = url[1]
            # 一旦匹配上就退出循环,节省资源
            break
    # 判断func是否有值
    if func:
        # 调用
        res = func(env)  # env是个大字典,里面含有信息,在后续的逻辑中可能还需要用到字典内的信息
    else:
        res = errors(env)
    return [res.encode('utf-8')]  # 将所有逻辑函数返回的字符串在此统一编码,发给客户端
​
​
if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)
    # 实时监测127.0.0.1:8080地址,一旦有客户端连接,会自动加括号调用run方法
    server.serve_forever()  # 启动服务端

 

基于wsgiref模块将代码拆分成urls.py路由文件,views.py视图文件和wsgiref通信文件三部分,后续加功能只需要在urls.py文件和view.py文件中加入对应功能即可
1.urls.py  路由与视图函数的对应关系
2.views.py  视图函数

让网页动态起来

静态网页:数据时写死的,万年不变
动态网页:
1.后端实时获取当前时间'传递'给前端页面展示
   2.后端从数据库获取数据'传递'给前端页面展示
ps : 传递即渲染

获取当前时间

from datetime import datetime
def get_time(env):
    # 现在后端获取当前时间
    current_time = datetime.now().strftime('%Y-%m-%d %X')
    # 将获取的时间添加到HTML代码中的思路:
    # 1.先在<body>内指定位置用一串字符占位($$time$$)
    # 2.文件的形式读取HTML页面,对于计算机来说,html页面只是一串二进制数据
    # 3.用 r 模式对出来的是一串字符串,利用字符串替换,将拿到的时间和站位的字符串替换即可
    with open(r'templates/2get_time.html', 'r', encoding='utf-8') as f:
        data = f.read()
    data = data.replace('$$time$$', current_time)
    return data

 

从数据库中查询数据

jinja2:

上面的代码实现了一个简单的动态,我完全可以从数据库中查询数据,然后去替换我html中的对应内容,然后再发送给浏览器完成渲染。 
这个过程就相当于HTML模板渲染数据。 本质上就是HTML内容中利用一些特殊的符号来替换要展示的数据。 我这里用的特殊符号是我定义的,其实模板渲染有个现成的工具: jinja2
from jinja2 import Template
import pymysql
def get_db(env):
    conn = pymysql.connect(
        host = '1270.0.1',
        port = 3306,
        user = 'root',
        password = 'root',
        database = 'db4',
        charset = 'utf8',
        autocommit = True,
    )
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    sql = "select * form userinfo"
    cursor.execute(sql)
    data = cursor.fetchall()
    with open(r'templates/4get_db.html', 'r', encoding='utf-8')as f:
        data_user = f.read()
    temp = Template(data_user)
    res = temp.render(user_list = data)
    return res

 

<div class="container"><div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h2 class="text-center">用户数据展示</h2>
            <table class="table table-hover table-bordered table-striped">
                <thead>
                    <tr>
                        <th>id</th>
                        <th>username</th>
                        <th>password</th>
                    </tr>
                </thead>
                <tbody>
                    {%for user_dict in user_list%}
                        <tr>
                            <td>{{user_dict.id}}</td>
                            <td>{{user_dict.name}}</td>
                            <td>{{user_dict.password}}</td>
                        </tr>
                    {%endfor%}
                </tbody>
            </table>
        </div></div>

 

模板渲染
后端生成的数据直接传递给前端页面使用(并且前端页面可以灵活的操作改数据) >>> 模板语法

模板渲染 模板语法需要依赖于第三方模块
pip install jinja2

模板语法 jinja2支持前端直接使用类似于python的语法操作数据,语法如下:
  取值:
    <p>{{ user_dic }}</p>
    <p>{{ user_dic.name }}</p>
    <p>{{ user_dic['password'] }}</p>
    <p>{{ user_dic.get('name') }}</p>
    
  for循环:
   {% for user in user_dict %}  <!--[{},{},{},{}]-->
        <tr>
            <td>{{ user.id }}</td>
            <td>{{ user.name }}</td>
            <td>{{ user.password }}</td>
        </tr>
    {% endfor %}

 

wsgiref 与 Django框架初识

正戏 Django

python三大主流web框架:
1. Django:大而全,自带了很多功能模块,类似于航空母舰 (缺点:有点笨重)
2. Flask:短小精悍,自带的功能模块特别少,大部分都是依赖于第三方模块(小而轻)
3. Tornado:异步非阻塞 主要用在处理高io 多路复用的情况 可以写游戏后端

a:socket
b:路由与视图函数
c:模板渲染
​
Django:
    a用的别人的 wsgiref
    b自己写的
    c自己写的
Flask:
    a用的别人的 werkzeug
    b自己写的
    c用的别人的 jinja2
Tornado:
    a,b,c都是自己写的
使用Django注意事项(*****************************):
1.计算机的名称不能有中文
2.一个pycharm窗口就是一个项目,不要多个项目放在一个窗口里面
3.项目名不能起中文

一.djang下载 推荐下载1.11.11版本

命令行直接下载
pip3 install django==1.11.11
pycharm下载
验证是否下载成功:
django-admin

二.创建django项目的方式

1.命令行创建

创建django项目:
    django-admin startproject 项目名
创建app应用(在项目名下):
    django-admin startapp 应用名
    python3 manage.py startapp 应用名
启动django项目
    python3 manage.py runserver 
ps:用命令行创建django默认不会自动创建templates文件夹
需要你手动自己创建(注意该文件夹路径是否被添加配置文件中)   
Ctrl+c 停止运行

 

2.pycharm创建

FILE >>> new project 选择第二个django 需要注意名字不能有中文,选择本地的解释器,勾选后台管理
创建app
    pycharm命令行创建
        python3 manage.py startapp 应用名
    Tools下面run manage task功能栏
        startapp 应用名
启动点小绿色箭头

 

wsgiref 与 Django框架初识

wsgiref 与 Django框架初识

wsgiref 与 Django框架初识

三.django各个文件的作用

1.应用名文件

migrations  数据库迁移记录相关数据
admin.py    django后台管理相关
models.py   模型表相关
views.py    视图函数相关
apps.py     应用注册相关
texte.py    测试文件
views.py    视图函数

 

2.项目名文件

settings.py  配置文件
urls.py     路由与视图函数的映射关系

 

3.templates

项目用到的所有的html文件

 

4.manage.py

django入口文件

 

四.注意新创建的app需要在配置文件中注册才能生效(*******)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    '应用名.apps.App01Config'  # 可以用全称
    '应用名'                # 也可以简写

 

]

五.django小白必会三板斧

from django.shortcuts import render,HttpResponse,redirect

 

1.HttpResponse 返回字符串

return HttpResponse('字符串')

# 例:
def index(request):
    return HttpResponse('hello first django')  # 返回字符串

 

 

2.render 返回HTML页面

return render()  # 第一个参数request,第二个参数HTML,第三个参数字典

# 例:
def login(request):
    user_dict = {'username':'haha'}
    return render(request, '01 login.html', {'data':user_dict})  # 返回html页面

 

3.redirect 重定向

def home(request):
    return redirect('/login/')  # 重定向

 

 

 

相关文章:

  • 2021-11-04
  • 2022-12-23
  • 2021-12-25
  • 2021-09-01
  • 2020-03-31
  • 2021-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-04-26
  • 2022-01-14
  • 2021-12-25
  • 2022-12-27
相关资源
相似解决方案