python笔记5:编写Web框架支持路由正则、log功能

Table of Contents

02进程与程序的区别

03关注股票

04取消关注

05更新备注

06 url编码解码

07 log日志


01功能介绍

需求:路由支持正则,添加、删除关注,修改备注信息(url编码),logging日志模块

02进程与程序的区别

程序(静态)为在硬盘中的二进制exe文件,运行时创建一个进程(动态)

同一个程序可以多次运行,对应多个进程(如同用菜谱做菜)

进程可以拥有、使用操作系统的资源

03关注股票

需求:实现添加关注功能:取出参数值,在mysql插入数据

通过正则使带参url路由对应该函数

@route(r"/add/\d+\.py")

def add_focus():

    return "add ok"

\d+接收参数

‘.’号在正则匹配中需要用\转义

此时字典的样子如下:

url_func_dict = {

          r"/add/\d+\.py$": add_focus,

          r"/index\.py": index

        }

在application中处理url

#原

func = url_func_dict[path_info]  # 如果path_info是/index.py那么也就意味着取 index函数的引用

        # 那么将来调用的时候,就调用了不一样的函数

        response_body = func()

#改为

for r_url, func in url_func_dict.items():

            ret = re.match(r_url, path_info)   # 当此次for循环的时候,r_url是原字符串 (正则表达式),而func指向了这个正则表达式匹配的情况下

                                                # 需要调用的函数

            if ret:

                response_body = func()

此处获得了正则的匹配结果ret,但应该在add_focus取值,而不应该在外面取,如果在application中取值,接下来所有带分组的都要取,所以直接传回fun

if ret:

                response_body = func(ret)

在函数中接收,每个函数的定义时都需要定义形参

@route(r"/add/(\d+)\.py")

def add_focus(ret):

    stock_code=ret.group(1)

    return "add (%s) ok" % stock_code

(\d+)作为一个group,否则取时会报错:产生了异常:no such group

添加update.html模板文件

在index中引入jQuery,添加js函数:

<script>

        $(document).ready(function(){

 

                $("input[name='toAdd']").each(function(){ 

                    var currentAdd = $(this); 

                    currentAdd.click(function(){ 

                        code = $(this).attr("systemIdVaule");

                        // alert("/add/" + code + ".html");

                        $.get("/add/" + code + ".py", function(data, status){

                            alert("数据: " + data + "\n状态: " + status);

                        });

                    }); 

                }); 

        });

    </script>

点击添加可以获得成功弹框提示

浏览器先要服务器再给框架,处理完了再返回浏览器,常常看不到处理过程。只有保证有返回值,才能根据返回信息处理

目前已经获取了股票代码,还要判断是否有这只股票,如果有,则判断是否已经关注过

select * from info where code="000007";

select * from focus where info_id="2";

没关注过则添加关注

insert into focus (info_id) values ("1");

insert into focus (info_id) select id from info where code="";

Add函数:

@route(r"/add/(\d+)\.py")

def add_focus(ret):

    stock_code=ret.group(1)

    #判断是否有这只股票

    conn = pymysql.connect(host='localhost',port=3306,user='root',password='123456',database='stock_db',charset='utf8')

    cursor = conn.cursor()

    # sql = """select * from info where code=%s;"""

    sql = """select * from info where code=%s;"""

    cursor.execute(sql,(stock_code))#防止sql注入

    data_from_mysql=cursor.fetchone()

    if not data_from_mysql:

        cursor.close()

        conn.close()

        return "该code不存在"

    #如果有,则判断是否已经关注过

    sql = """select * from focus where info_id=%s;"""

    cursor.execute(sql,(data_from_mysql[0]))

    #如果查出来了,则已关注过

    if cursor.fetchone():

        # data_from_mysql=cursor.fetchone()

        cursor.close()

        conn.close()

        return "已关注过"

    #添加关注

    sql = """insert into focus (info_id) values ("%s");"""

    cursor.execute(sql,(data_from_mysql[0]))

    #添加需要提交事务

    conn.commit()

    cursor.close()

    conn.close()

   

    return "add (%s) ok" % data_from_mysql[0]

04取消关注

添加可以通过get方式使用url参数,但股票code是明码,也可以使用post方式

先取出代码,判断各种条件合适,操作数据库

查看前端点击按钮时发送的请求,确定装饰器的url

@route(r"/del/(\d+)\.py")

判断将没有关注过改为非法请求

按照info_id删除关注

delete from focus where info_id =”1”;

此时注意将个人中心使用的模板中的修改备注、删除关注的代码改为股票代码,

并在模板html中添加js:

<script>

        $(document).ready(function(){

 

                $("input[name='toDel']").each(function(){ 

                    var currentAdd = $(this); 

                    currentAdd.click(function(){ 

                        code = $(this).attr("systemIdVaule");

                        // alert("/add/" + code + ".html");

                        $.get("/del/" + code + ".py", function(data, status){

                            alert("数据: " + data + "\n状态: " + status);

                        });

                    }); 

                }); 

        });

    </script>

05更新备注

点击按钮,打开新页面修改,新页面中会显示原先的信息

点击修改按钮时,可以看到服务器发出请求:update/000007.py

添加新路由:

@route(r"/update/(\d+)\.py")

def update_page(ret):

打开使用的模板修改为update.html

查看该update.html结构,其中修改栏形如

正在修改:

{%code%}

{%note_info%}

所以应先获得股票代码、原备注信息,其中股票代码由url正则参数解析可获取

select note_info,info_id from focus where info_id = (select id from info where code = "300268");

用查出来的东西替换html模板中的code等内容

content=re.sub(r"\{%code%\}",stock_code,content)   

    content=re.sub(r"\{%note_info%\}",data_from_mysql[0],content)

显示该页面的函数为:

@route(r"/update/(\d+)\.py")

def update_page(ret):

    '''显示修改的页面'''

    stock_code=ret.group(1)

    with open("./templates/update.html", encoding='UTF-8') as f:

        content = f.read()

    conn = pymysql.connect(host='localhost',port=3306,user='root',password='123456',database='stock_db',charset='utf8')

    cursor = conn.cursor()

    #根据股票代码查询相关信息

    sql = """select note_info,info_id from focus where info_id = (select id from info where code = %s);

"""

    cursor.execute(sql,(stock_code))

    data_from_mysql = cursor.fetchone() 

    cursor.close()

    conn.close()

   

    content=re.sub(r"\{%code%\}",stock_code,content)    

    content=re.sub(r"\{%note_info%\}",data_from_mysql[0],content)

 

    # 3. 返回模板数据

    return content

点击修改按钮可以看到浏览器请求:

update/ {%code%}/ #note_info.py

所以对多参数update的路由需要重新定义

正则数字用d,字符可用w但无法匹配空格等,用*可匹配

@route(r"/update/(\d+)/(.*+)\.py")

def save_update(ret):

    '''保存修改的页面'''

    stock_code=ret.group(1)

    note_info=ret.group(2)

修改note信息

update focus set note_info="hhhh" where info_id =(select id from info where code= "000036");

保存更新函数

@route(r"/update/(\d+)/(.*)\.py")

def save_update(ret):

    '''保存修改的页面'''

    stock_code=ret.group(1)

    note_info=ret.group(2)

    #判断是否有这只股票

    conn = pymysql.connect(host='localhost',port=3306,user='root',password='123456',database='stock_db',charset='utf8')

    cursor = conn.cursor()

    # sql = """select * from info where code=%s;"""

    sql = """select * from info where code=%s;"""

    cursor.execute(sql,(stock_code))#防止sql注入

    if not cursor.fetchone():

        cursor.close()

        conn.close()

        return "该code不存在"

    #修改note

    sql = """update focus set note_info=%s where info_id =(select id from info where code= %s);"""

    cursor.execute(sql,(note_info,stock_code))

    #更新需要提交事务

    conn.commit()

    cursor.close()

    conn.close()

   

    return "update (%s) ok" % stock_code

存在问题:控空格乱码

(。・∀・)ノ゙原来东哥还有建站http://howdoit.cn/

现在看的系列对应的是《从零编写web框架》http://books.howdoit.cn/012-MiniWeb/

哇,一直愁找不到这个html的课件,每次看课上展示用的都是localhost就很奇怪,觉得做了这么多应该是可以直接放成网站的,果然有啊

06 url编码解码

url中的参数,如中文、/等特殊符号,如果不转码,有可能会与url格式冲突,所以会进行编码(一般自动转了)防止解析出错。不是页面内容的编码,是url的编码

frame向mysql保存前要解码

原本直接获取保存

note_info=ret.group(2)

urllib.parse模块能够实现url的编码(quote)解码(unquote)

note_info=urllib.parse.unquote(note_info)

浏览器中多个空格会按一个空格来处理

各个地方的功能独立成一个程序,通过协议实现了解耦

07 log日志

解bug两种方式:

  1. 根据现象缩小范围
  2. Log日志(可以调整级别的print)

日志分5级:1.debug 2.info 3.warring 4.error 5.critical(默认warning)

日志输出方式:控制台、日志文件

日志打印:

import logging

logging.info('log-info')

logging.warning('log-warning')

输出(默认warning以上):

WARNING:root:log-warning

添加级别设置:

logging.basicConfig(level=logging.DEBUG)

则能够全部显示

设置格式:

logging.basicConfig(level=logging.DEBUG,format='%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s')

输出:

2020-5-23 12:14:15 - log1.py[line:5] WARNING:log-warning

将日志保存到文件:w覆写追加

logging.basicConfig(level=logging.DEBUG,

       filename='./log.txt',

       filemode='w',

       format='%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s')

黑客在攻击完之后一定会把记录痕迹(log)清理掉(擦完屁股再走)

排查bug时避免了复现的麻烦

一般流程:

import logging

logger=logging.getLogger()#如果不创建logger,就是默认root

logger.setLevel(logging.INFO)#总开关

#创建写入handler

logfile='./log.txt'

fh=logging.FileHandler(logfile,mode='a')

fh.setLevel(logging.DEBUG)#输出到log文件等级的开关

#创建控制台handler

ch=logging.StreamHandler()

ch.setLevel(logging.WARNING)

#定义输出格式

formatter=logging.Formatter("%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s")

fh.setFormatter(formatter)

ch.setFormatter(formatter)

#将logger与handler关联

logger.addHandler(fh)

logger.addHandler(ch)

 

logging.info('log-info')

logging.warning('log-warning')

使用在服务器中:

def application(env, set_header):

    # 1. 调用set_header指向的函数,将response_header传递过去

    status = '200 OK'

    response_headers = [('Content-Type', 'text/html; charset=UTF-8')]

    set_header(status, response_headers)

 

    # 提取url

    path_info = env['PATH_INFO']  # /index.py

    logging.basicConfig(level=logging.DEBUG,

        filename='./log.txt',

        filemode='w',

        format='%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s')

    logging.info('访问了%s'%path_info)

    try:

 

        for r_url, func in url_func_dict.items():

            ret = re.match(r_url, path_info)   # 当此次for循环的时候,r_url是原字符串 (正则表达式),而func指向了这个正则表达式匹配的情况下

                                                # 需要调用的函数

            if ret:

                response_body = func(ret)

    except Exception as ret:

        logging.error('产生了异常%s'%str(ret))

        return "产生了异常:%s" % str(ret)#保证返回web服务器有body

        # response_body = "-----not found you page-----"

 

    # 2. 通过return 将body返回

    return response_body

访问人数统计:统计log,找用户群测试

主从服务器也可用框架配(访问不同服务器ip

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值