Python开发web服务器——留言板

本次博客的主题:留言板,希望能给大家一些帮助。另外本篇需要以上篇《搭建简易服务器》为基础。

所需知识

python3flask基础操作

sqlite3数据库操作基础

为何是sqlite3?相较于现在大火的mysql,sqlite3有以下优点:
免安装
免配置
数据库文件易转移
语法与mysql极其相似(python库操作方式也几乎相同)
故而选sqlite作为学习web开发存储的数据库是十分方便的

html基础

所需第三方python库

  • flask
  • jinja2

梳理

本次我们要完成的是留言板,即表单提交查询。
故而,本次的页面分为三个:
1. / 显示提交留言的表单
2. /update 留言信息提交至次
3. /view 查看留言
首先,让我们看看在py3中如何操作sqlite3数据库

#coding=utf-8
#操作sqlite3的库(自带)
import sqlite3
#链接sqlite3数据库
#如果文件不存在自动创建
conn = sqlite3.connect('a.db')
# 创建一个Cursor:
cursor = conn.cursor()
# 执行一条SQL语句,创建user表:
cursor.execute('create table message (id integer primary key,name varchar(64),mail varchar(64))')
#提交conn.commit
conn.commit()

#插入数据
name = 'lyt'
mail = '[email protected]'
#sqlite中是用?当占位符,几个问好后面跟几个参数
cursor.execute('insert into message (name,mail) values (?,?)',[name,mail])
#增删改必须commit
conn.commit()

#查询数据
cursor.execute('select * from message')
#获取结果,返回的是一个列表
num = cursor.fetchall()
print(num)
#关闭
cursor.close()
conn.close()

下一步,写一个html表单提交页面
templates/form.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>联系我们title>
head>
<body>
<form action="/update" method="POST">
    姓名:<input type = "text" name = "name">
    <br>
    邮箱:<input type = "text" name = "mail">
    <br>
    留言:<input type = "text" name = "word">
    <br>
    <button type = "submit">提交buttonform>
<a href="view?p=1">查看留言a>
body>
html>

接下来,那就很简单了,用flask的装饰器写/,/update两个页面
Main.py

from flask import Flask
from flask import request
from flask import render_template
import datetime
import sqlite3

初始化数据库
conn = sqlite3.connect('../test.db')
cursor = conn.cursor()  
try:
    cursor.execute('create table message (id integer primary key,name varchar(64),mail varchar(64),word text,time_at datetime)')
except Exception as e:
    print('数据表已存在')

app = Flask(__name__)
#表单
@app.route('/',methods=['GET','POST'])
def home():
    return render_template('form.html')

#提交
@app.route('/update',methods=['POST'])
def update():
    #获取post来的数据
    name = request.form['name']
    mail = request.form['mail']
    word = request.form['word']
    #生成当前时间
    now = datetime.datetime.now()
    now = now.strftime('%Y-%m-%d %H:%M:%S')

    if(name and mail and word):
        cursor.execute('insert into message (name,mail,word,time_at) values (?, ? ,? ,?)', [name,mail,word,now ])
        conn.commit()
        return "提交成功"
    return "不能为空"

if __name__ == '__main__':
    app.run()

然后,查看留言页面

@app.route('/view',methods=['GET'])
def view():
    cursor.execute('select count(id) from message')
    num = cursor.fetchall()
    num = int(num[0][0])
    #最大页数
    all_p = num // 5 +  1

    p = int(request.args.get('p'))

    # 显示页数列表(5个)
    lis = ()
    if(all_p >= 5):
        if(p-2 >= 1 and p+2 <= all_p):
            lis = range(p-2,p+3)
        elif(p-2 >= 1 and p+2 > all_p):
            lis = range(all_p-4,all_p+1)
        else:
            lis = range(1,6)
    else:
        lis = range(1,all_p+1)

    n = cursor.execute('select name,word,time_at from message where id BETWEEN ? and ?', [p*5-4,p*5])
    mess = cursor.fetchall()
    return render_template('view.html',p = p,mess = mess,all_p = all_p,lis = lis)

查看留言的html模板templates/view.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>查看留言title>
head>
<body>
姓名   留言   时间
<br>
{% for i in mess %}
{{i[0]}}   {{i[1]}}   {{i[2]}}<br>
{% endfor %}

{% if p != 1%}
<a href="view?p=1">首页a>
<a href="view?p={{p-1}}">上一页a> 
{% endif %}

{% for j in lis %}

{% if j == p %}
{{j}}
{% else %}
<a href = "view?p={{j}}">{{j}}a>
{% endif %}

{% endfor %}

{% if p != all_p%}
<a href="view?p={{p+1}}">下一页a>
<a href="view?p={{all_p}}">尾页a>
{% endif %}

body>
html>

如此,这个留言小程序骨架已经好了。运行Main.py就能看到结果了

优化

表单小程序还得防止有些用户恶意刷单,我们得做一些优化,那么,就是设定一定时间内一个ip的提交次数是有限的。
这个怎么实现呢,先说说思路:
利用一个字典,存储提交留言的用户的ip及次数。当一段时间内此处大于限定值,那么提示操作频繁,这段时间过后,清空字典。

#记录用户提交次数
global user_ip
user_ip = {}

#限制单个ip提交次数,次/小时,0为无限制
global update_n
update_n = 20

@app.route('/update',methods=['POST'])
def update():
    name = request.form['name']
    mail = request.form['mail']
    word = request.form['word']
    now = datetime.datetime.now()
    now = now.strftime('%Y-%m-%d %H:%M:%S')

    if(name and mail and word):
        if(update_n != 0):
            ip = request.remote_addr
            if(ip not in user_ip):
                user_ip[ip] = 1
            else:
                user_ip[ip] += 1
            if(user_ip[ip] > update_n):
                return "操作过于频繁"
            else:
                cursor.execute('insert into message (name,mail,word,time_at) values (?, ? ,? ,?)', [name,mail,word,now ])
                conn.commit()
                return "提交成功"
        else:
            cursor.execute('insert into message (name,mail,word,time_at) values (?, ? ,? ,?)', [name, mail, word, now])
            conn.commit()
            return "提交成功"
    return "不能为空"

现在已经开始限制提交了。
那么还要做的是定时清空字典,用到的是threading.Timer()
下面是一个定时器的示例,每隔5.5秒执行一次:

#coding = utf-8
#定时器
import threading
def fun_timer():
    print('Hello Timer!')
    global timer
    timer = threading.Timer(5.5, fun_timer)
    timer.start()

timer = threading.Timer(1, fun_timer)
timer.start()

那么,根据这个写一个定时清空字典的定时器,解决问题。

#刷新ip限制时间/s
global del_ip_time
del_ip_time = 3600

def del_ip():
    user_ip.clear()
    print('清除ip限制')
    global timer
    timer = threading.Timer(del_ip_time, del_ip)
    timer.start()

timer = threading.Timer(1, del_ip)
timer.start()

成品

github:
https://github.com/City-Zero/flask_form
欢迎大家交流

你可能感兴趣的:(python,web)