Flask Web 开发实战
The Flask Mega-Tutorial
wenshaofeng/bikeMs: 学习用react写共享单车后台管理系统 (github.com)
计算机毕业设计springboot校园共享单车系统的设计与实现0v1439[附源码]
实战开始
创建项目
第一步就遇到困难,完全不知道如何下手,
选择GitHub上公开的项目进行补充修改,操作系统采用Windows 11,数据库采用MySQL,后端框架采用Flask,编程语言是python
Flask框架学习
搭建Flask环境:
1 | pip install flask |
启动开发服务器:
1 | 在虚拟环境中运行(提前激活虚拟环境 pipenv shell) |
项目配置:
1 | 在项目根目录下创建config.py文件 |
使用pipenv安装扩展Flask-WTF处理表单:
pipenv install flask-wtf
路由
路由就是URL和Python函数的映射关系,说的再明白点,就是客户端请求哪个路径交给哪个函数处理的问题。
通过给函数添加装饰器@app.route,即可定义路由,装饰器的参数即为对应的URL。
也就是说装饰器的参数设置成什么就会匹配什么资源路径(Path to resource)
@app.route(‘/hello’)
访问http://127.0.0.1:5000/hello,由于该访问地址URL匹配'/hello',所以将被处理。
动态控制路由(重定向)
通过redirect()函数即可动态控制路由。
return redirect(url_for(‘login’))
URL参数
有时候,我们希望接受URL上附带的参数,此时可以通过在装饰器上添加格式的内容,来对应URL传递的参数
装饰器
装饰器就是在一个函数里嵌套一个或者多个函数,在这些函数里使用了顶层函数的参数(不管是参数是值还是函数),然后构造出来一个装饰器,在调用时对其他值或者函数用装饰器,最终输出时参数的值被装载了装饰器的函数或值替换(赋值)。
python装饰器总结一句话:采用了闭包的思路(内外函数嵌套,内函数引用外函数作用域下的非全局变量,外函数返回内函数的引用),在不改变原函数代码的前提下为函数增添新的功能
@wraps(func) # 继承原函数,调用时不改变函数原含义
1 | def a_new_decorator(a_func): |
print(a_function_requiring_decoration.name)
Output: wrapTheFunction
使用装饰器会导致调用函数的名称被覆盖成装饰器的内层函数,这里用functools.wraps装饰内层函数就可以解决这个问题
初始化
1 | def __init__(self, host, user, password, db, charset): |
WTF表单
| 字段 | 说明 | 对应的HTML表示 |
|---|---|---|
| StringField | 文本字段 | |
| TextAreaField | 多行文本字段 | |
| PasswordField | 密码文本字段 | |
| HiddenField | 隐藏文本字段 | |
| DateField | 文本字段,值为datetime.date格式 | |
| DateTimeField | 文本字段,值为datetime.datetime格式 | |
| IntegerField | 文本字段,值为整数 | |
| DecimalField | 文本字段,值为decimal.Decimal | |
| FloatField | 文本字段,值为浮点数 | |
| BooleanField | 复选框,值为True和False | |
| RadioField | 一组单选框 | |
| SelectField | 下拉列表 | |
| SelectMultipleField | 下拉列表,可选择多个值 | |
| FileField | 文件上传字段 | |
| SubmitField | 表单提交按钮 | |
| FormField | 把表单作为字段嵌入另一个表单 | |
| FieldList | 一组指定类型的字段 |
WTF表单验证
| 验证器 | 说明 |
|---|---|
| DataRequired | 确保字段中有数据 |
| 验证电子邮件地址 | |
| EqualTo | 比较两个字段的值;常用于要求输入两次密码进行确认的情况 |
| InputRequired | 确保字段中有数据 |
| IPAddress | 验证IPv4网络地址 |
| Length | 验证输入字符串的长度在数字范围内 |
| NumberRange | 验证输入的值在数字范围内 |
| Optional | 无输入值时跳过其他验证函数 |
| Required | 确保字段中有数据 |
| Regexp | 使用正则表达式验证输入值 |
| URL | 验证URL |
| AnyOf | 确保输入值在可选值列表中 |
| NoneOf | 确保输入值不在可选值列表中 |
实例化字段类常用参数
| 参数 | 说明 |
|---|---|
| label | 标签 |
| validators | 验证器 |
| render_kw | 渲染控件的属性,一个字典,用来设置对应的HTML标签的属性 |
| default | 默认值 |
| filters | 过滤器 |
| description | 描述信息 |
| widget | 渲染控件 |
WTF表单安全
Flask-WTF内置了CSRF保护,可以抵御跨站请求伪造攻击。
跨站请求伪造(CSRF)是一种冒充受信任用户,向服务器发送非预期请求的攻击方式。例如,这些非预期请求可能是通过在跳转链接后的 URL 中加入恶意参数来完成:
表单中包含一个隐藏字段csrf_token,用来存放CSRF令牌,这个令牌是一个加密字符串,Flask-WTF使用这个令牌验证请求中表单数据的真伪。
默认情况下,使用程序密钥来CSRF令牌进行签名:
1 | app.secret_key = "secret string" |
处理表单数据
- 解析请求,获取表单数据
- 对数据进行必要的转换,比如将勾选框的值转换成Python的布尔值
- 对数据进行验证,确保数据要求,同时验证CSRF令牌
- 如果验证未通过则需要生成错误信息,并在模板中渲染表单显示错误信息,让用户可以修正
- 如果通过验证,则将数据保存到数据库中,或者执行其他操作
提交表单
| 属性 | 默认值 | 说明 |
|---|---|---|
| action | 当前URL,即页面对应的URL | 表单提交时发送请求的目标URL |
| method | GET | 表单提交时使用的HTTP方法 |
| enctype | application/x-www-form-urlencoded | 请求的数据编码方式 |
| autocomplete | on | 浏览器是否可以自动完成表单 |
验证表单数据
客户端验证:在浏览器中使用JavaScript验证表单数据,可以提高用户体验,但是不可靠,因为用户可以禁用JavaScript。
服务器端验证:在服务器端验证表单数据,可以确保数据符合要求,但是会增加服务器的负载。
使用POST方法提交的表单,其数据会被Flask解析为一个字典,可以通过request.form来访问这个字典。
使用GET方法提交的表单,其数据会被Flask解析为一个不可变的MultiDict,可以通过request.args来访问这个字典。
tools.py
1 | def create_all(self): |
bike.sql
– 为了自动读取本文件并初始化, 需要在每条语句后加 —-
– 但注意最后一句不要加 —-
项目配置
为什么需要使用自己的配置?
假设你在做一个博客,有十个视图函数都定义了每页显示的文章数。当你写好以后,发现每页的文章太多,想把这个值改小一点,这时你要找到这十个视图函数,分别修改这个值,很蠢吧?使用配置你就使用一行控制所有的变量:app.config['POST_PER_PAGE'] = 12
设置配置
- 直接写出配置的值,像上面那样。
- 对于不适合写在程序里的配置,比如密码等,需要把配置写入系统环境变量,然后使用os模块的getenv()方法获取,第二个参数作为默认值
1 | import os |
如果使用虚拟环境,设置环境变量时注意要激活虚拟环境,同时不要给变量值加引号。
set MAIL_USERNAME=me@greyli.com # 结果是'me@greyli.com'set MAIL_USERNAME='me@greyli.com' # 结果是"'me@greyli.com'"
处理配置
- 直接写入主脚本
- 单独的配置文件
- 通过Json文件,app.config.from_json
1 | { |
- 通过 python文件,app.config.from_object 或 app.config.from_pyfile
1 | SECRET_KEY = 'some secret words' |
app.secret_key、cookie、session
会话技术、Cookies、Session详解
程序可以把数据存储在用户会话中,用户会话是-种私有存储,默认情况下,它会保存在客户端cookie中。Flask提供了session对象来操作用户会话。session 是基于cookie实现, 保存在服务端的键值对(形式为 {随机字符串:‘xxxxxx’}), 同时在浏览器中的cookie中也对应一相同的随机字符串,用来再次请求的时候验证
Flask中的session是存在浏览器中 默认key是session(加密的cookie),使用session时要设置一个密钥app. secret_ key
Flask API
flash函数 - 闪现信息
flask-flash函数
闪现信息就是 只展示一次的数据/参数.
应用:
比如进入首页只刷一次的广告.
render_template和redirect函数及其区别
Flask render_template和redirect的区别
render_template函数
render_template函数是Flask框架中的一个重要函数,其主要作用是将指定的模板文件渲染成HTML页面并返回给客户端。该函数通常用于将动态数据与静态的HTML模板结合,实现页面的动态展示。
redirect函数
redirect函数是Flask框架中的另一个重要函数,其主要作用是将用户重定向到指定的URL。当我们在处理某些请求时,希望将用户重定向到另一个URL时,可以使用redirect函数实现这个功能。
区别
- render_template函数用于渲染模板,返回HTML页面;redirect函数用于重定向,将用户跳转到另一个URL;
- render_template函数常用于页面展示,并且需要与路由函数配合使用;redirect函数常用于重定向到其他页面或执行其他操作;
- render_template函数返回的是生成的HTML页面代码;redirect函数返回的是一个新的URL,用户的浏览器将会跳转到该URL。
Jinja2 模板继承
模板继承
Python web 框架 Flask 模板使用
Django 使用了“模板继承”的概念:这就是{% extends "base.html" %}所做的事。它意味着 “首先载入名为 ‘base’ 的模板中的内容到当前模板,然后再处理本模板中的其余内容。”总之,模板继承让你在模板间大大减少冗余内容:每一个模板只需要定义它独特的部分即可。
将模板转换为完整的HTML页面的操作称为渲染。 为了渲染模板,需要从Flask框架中导入一个名为render_template()的函数。 该函数需要传入模板文件名和模板参数的变量列表,并返回模板中所有占位符都用实际变量值替换后的字符串结果。
render_template()函数调用Flask框架原生依赖的Jinja2模板引擎。 Jinja2用render_template()函数传入的参数中的相应值替换{{...}}块。
模板也支持在{%...%}块内使用控制语句
1 | # 条件语句 |
error
ConnectionRefusedError: [WinError 10061] 由于目标计算机积极拒绝,无法连接。
猜测原因:MySQL未连接成功
尝试解决方法:重新下载并配置环境
MySQL8.0的安装、配置、启动服务和登录及配置环境变量
下载并配置好后,错误代码发生变化,证明思路正确
New error:
pymysql.err.OperationalError: (1045, “Access denied for user ‘root‘@’localhost’ (using password: YES)”)
原因:数据库user:root的连接密钥错误
更换所有__init__的初始化数据库函数的参数
util = MySQLTools(‘localhost’, ‘root’, ‘Qq13239349089’, ‘sharebike’, ‘utf8’) //Qq13239349089是我的数据库密钥
New error:
AttributeError: ‘Flask’ object has no attribute ‘before_first_request’. Did you mean: ‘_got_first_request’?
原因:flask2.3.0已经弃用钩子函数’before_first_request’
solution:pip install Flask==2.2.5
用搜索引擎查找相关问题,答案比较少,有一篇说明是2.3.0版本删除了钩子函数,但没有对更新后如何修改进行说明的贴子,因此选择退回版本
项目跑成功了!
经过一番折腾,这该死的项目终于能跑起来了,之后就是看懂再增删改了,明天把文档写一写
要做的内容:
单车管理
骑行者管理
押金管理
骑行管理
其他功能:查询统计、用户权限管理、异常处理(单车故障、押金不足、骑行者黑名单等)等
从网页开始读代码
开发环境:
Windows系统
Pycharm 软件
前端框架 Bootstrap
后端框架 Flask
数据库 MySQL
<link href = "/static/bootstrap/dist/css/bootstrap.min.css" rel = "stylesheet">
采用了bootstrap框架,但版本较低,之后可以考虑更新版本
尝试增加功能:用户界面,点击右上角的图像可以转到
鼠标悬停页面头部用户图像出现下拉菜单的实现
点击头像选择图片更换头像
点击头像更换头像
修改内容-删去同济相关文字
抠图好tm麻烦
实现功能
1.自动登录 session与cookie
2.数据库加密 python cryptography
3.动态生成导航栏 JS改写
使用最小代价去更新,利用Web Components技术
4.解决一下网页打开慢的问题
5.并发量大的时候,数据库会崩溃,需要解决 测试
解决高并发的系统设计
网站性能测试指标及网站压力测试
6.重新设计页面 优秀的交互设计(比如说单车点击可借)
7.无障碍功能设计
8.小功能 (更换语言,更换主题,更换背景,更换字体)