• wsgiref 与 Django框架初识


    前戏:

    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 Host: 127.0.0.1:8080 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 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,en;q=0.8 ' '''

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

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

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

     

     

    处女版自定义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
    
    hello Django')
        conn.colse()

    以上就是web 框架的本质。

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

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

    如何让我们的Web服务根据用户请求的URL不同而返回不同的内容呢?
    我们发现,用户输入不同的url在服务端接收的请求是不一样的,区别在与
    b'GET /index HTTP/1.1 Host: 127.0.0.1:8080 .....
    里面多了/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
    
    ')  # TCP 流式协议特性
        data = data.decode('utf-8')
        current_path = data.split('
    ')[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()  # 启动服务端

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

    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 %}

    正戏 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 应用名
    启动点小绿色箭头

    三.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/')  # 重定向
     

     

  • 相关阅读:
    C#(99):C# 6.0 新特性(.NET Framework 4.6 与 Visual Studio 2015 )
    C#(99):C# 3.0 新特性2:( NET Framework 3.5 与 Visual Studio 2008 )隐式类型、对象、集合初始值设定项、匿名类型、匿名对象
    C#(99):C# 3.0 新特性1:( NET Framework 3.5 与 Visual Studio 2008 )自动实现属性、扩展方法、Lambda,Linq,表达式树
    Scrapy爬虫框架实战案例(适合小白人门)
    惊!Python居然可以读故事了(附源码)
    识别豆瓣登录滑动验证码(附源码)
    「找一找」考你眼力的时候到了!
    想知道「双十一」淘宝商家销售数据?快来看看!!!
    人工智能下的音频还能这样玩!!!!
    想增加你的词汇量吗?---教你如何爬取某贝单词
  • 原文地址:https://www.cnblogs.com/waller/p/11519000.html
Copyright © 2020-2023  润新知