打算在云服务器上部署一个 TODO LIST 来练手,也就是一个代办事项提醒表。
本节学习使用 flask 库制作出一个登录界面,并且使用Redis数据库实现账号密码加载功能,关于注册界面我们下次再加上。
注意!!!请确保你安装了 redis 数据库,否则会因为无法登录数据库而报错。
这节的芝士点如下:
操作系统:Windows10 家庭版
开发环境:Pycahrm Comunity 2022.3
Python解释器版本:Python3.8
第三方库:flask,redis
request是Flask框架中的一个全局变量,用于在视图函数中获取客户端请求中的数据和属性。
其类型为flask.request,包含HTTP请求的各种属性和方法,例如请求方法、URL、表单数据、文件数据、请求头等。
例如你想获取用户名和密码,在浏览器中输入以后点击Login进行POST请求提交表单:
那么在代码中应该使用以下代码获取登录信息:
···
request.form["username"] # 获取用户名
request.form["password"] # 获取密码
····
你也可以使用这个来获取请求方式:
···
if request.method == 'POST':
···
redirect是Flask框架中的一个函数,用于重定向用户浏览器到其他URL或视图函数。
例如,完成登录后应该要跳转到另一个界面,这个跳转是如何实现的呢?用到的就是重定向:
···
# 跳转到/user/username
return redirect("/user/{}".format(request.form["username"]))
···
···
@app.route('/user/' , methods=['GET', 'POST'])
def todo_list(username):
# 处理事件
···
···
这段代码实现了动态路由功能,例如你是以 IoT_H2 的身份登录,那么将是以下这样:
现在我在Redis数据库中新建另一个用户:
用户名设置为 H2,密码设置123456
# 任务列表,在后期应设置为每个用户专用的列表
tasks = []
@app.route('/user/' , methods=['GET', 'POST'])
def todo_list(username):
global tasks
# 收到post请求则提交表单,添加代办任务
if request.method == 'POST':
task = request.form['task']
tasks.append(task)
# 收到GET请求则判断是否收到删除操作
elif request.method == 'GET':
delete_task = request.args.get('delete_task')
# 删除任务操作
if delete_task in tasks:
tasks.remove(delete_task)
# 不管什么请求,结束后都动态刷新页面
return render_template('todo.html', tasks=tasks,username = username)
Jinja2是一个流行的Python模板引擎,被广泛应用于Flask和Django等Web框架中。Jinja2模板引擎支持多种语法和语言扩展,包括控制流、变量替换、模板继承、过滤器等功能。
其实就是可以在其中写类似Python命令的一种规则,后缀名依旧是html。
下面是一个举例:
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{ title }}title>
head>
<body>
<h1>{{ title }}h1>
{% for item in items %}
<div>{{ item }}div>
{% endfor %}
body>
html>
title 和 items 都是我们使用 render_template 传递进去的参数。
不理解也没关系,整理好最后的工程然后阅读几遍即可:
注释我都写在了代码之中:
from flask import Flask, render_template,request,redirect
import redis
app = Flask(__name__)
# 连接 Redis 数据库
r = redis.Redis(host='127.0.0.1', port=6379,charset='utf-8', decode_responses=True)
def LoginTest(a,b):
if a == b:
return True
else:
return False
# 不管是/login 还是/ 都会进入到登录界面
@app.route('/')
@app.route('/login', methods=['GET', 'POST'])
def login():
# 收到的是POST请求
if request.method == 'POST':
# 处理登录表单提交的数据
# 与数据库比对登录信息,密码正确则重定向至用户界面
if LoginTest(request.form["password"],r.get(request.form["username"])):
print("Login Sucessfully")
return redirect("/user/{}".format(request.form["username"]))
# 密码错误
else:
return "ERROR PASSWD"
# 只能收到POST和GET请求,不是POST则是GET,返回登录界面
else:
# 显示登录表单页面
return render_template('login.html')
# 任务列表,在后期应设置为每个用户专用的列表
tasks = []
@app.route('/user/' , methods=['GET', 'POST'])
def todo_list(username):
global tasks
# 收到post请求则提交表单,添加代办任务
if request.method == 'POST':
task = request.form['task']
tasks.append(task)
# 收到GET请求则判断是否收到删除操作
elif request.method == 'GET':
delete_task = request.args.get('delete_task')
# 删除任务操作
if delete_task in tasks:
tasks.remove(delete_task)
# 不管什么请求,结束后都动态刷新页面
return render_template('todo.html', tasks=tasks,username = username)
if __name__ == '__main__':
# 0.0.0.0代表广播地址,同一局域网的用户都能访问
# 端口号为5000,设置为专用端口(如80)需要管理员身份
app.run(host = "0.0.0.0", port = 5000)
todo.html
DOCTYPE html>
<html>
<head>
{% if username %} {# 如果传递了username参数,那么将选项卡标签为 To Do List, username #}
<title>To Do List, {{ username }}title>
{% else %} {# 否则只显示To Do List #}
<title>To Do Listtitle>
{% endif %} {# 用完了if语句要endif #}
head>
<body>
{% if username %}
<h1>To Do List, {{ username }}h1>
{% else %}
<h1>To Do List, userh1>
{% endif %}
{% if tasks %}
<ul>
{% for task in tasks %}
<li>{{ task }}
<a href="?delete_task={{ task }}">[X]a>
li>
{% endfor %}
ul>
{% else %}
<p>No tasks yet!p>
{% endif %}
<form method="POST">
<input type="text" name="task" placeholder="Enter a new task...">
<input type="submit" value="Add">
form>
body>
html>
login.html
DOCTYPE html>
<html>
<head>
<title>Logintitle>
head>
<body>
<h1>Loginh1>
<form method="POST" action="/login">
<label>Username:label>
<input type="text" name="username"><br><br>
<label>Password:label>
<input type="password" name="password"><br><br>
<input type="submit" value="Login">
form>
body>
html>
如果发生报错: