前言
Flask是一个用Python编写的轻量级Web应用框架。它最初由Armin Ronacher作为Werkzeug的一个子项目在2010年开发出来。Werkzeug是一个综合工具包,提供了各种用于Web应用开发的工具和函数。自发布以来,Flask因其简洁和灵活性而迅速受到开发者的欢迎。随着Python社区的增长,Flask也得到了不断的更新和改进,成为了Python Web开发中的主流框架之一。它拥有庞大的用户和贡献者社区。
除此之外,于当下大模型大爆发的时代,它是也非常适合给企业做私有大模型场景提供web页面。对于web初学者来说一个非常值得尝试的框架。
接下来我们从web基础概念、flask安装调试、路由、模版、蓝图、数据库操作、实战案例几个方面给大家介绍flask的使用。
一、Web应用基本概念
如果你是第一次开发Web应用程序,你需要首选了解一下几个概念,它们是IP地址、dns、url、http、https。
1. IP地址
IP地址是分配给网络上每个设备的唯一标识符。
它允许设备之间进行通信,分为IPv4和IPv6两种类型。
2. DNS(域名系统)
DNS是互联网上用于将域名转换为IP地址的系统。
它允许用户通过易于记忆的域名来访问网站,而不是记住复杂的数字IP地址。
3. URL(统一资源定位符)
它是互联网上资源的地址,包括网页、图片、视频等。
格式通常为:协议://域名:端口/路径?查询字符串#片段标识符。
4. HTTP(超文本传输协议)
HTTP是用于从Web服务器传输超文本到本地浏览器的协议。
它是Web通信的基础,支持客户端和服务器之间的请求和响应。
5. HTTPS(安全超文本传输协议)
HTTPS是HTTP的安全版本,通过SSL/TLS协议加密数据传输。
它保护数据免受中间人攻击和其他安全威胁。
以上这样介绍可能不够直观,举一些例子吧。
一个小姐姐去北京西单吃北京烤鸭,她要去的那家烤鸭店的名字就是域名,比如我们平时在浏览器里输入的taobaoc.om。而这家烤鸭店的地址门牌号就是IP,烤鸭店名和地址都在工商局有注册,这个工商局就是DNS服务器。URL是由域名和访问资源组成的。比如taobao.com/xxxxx. 这个xxxxx就是资源,你可以理解为烤鸭店里具体的包间或卡座以及烤鸭店提供的服务。
http和https的概念你可以理解成写信和和回信的过程,http就是没有加密的信件,一个人投诉物业给有关部门写信,主管部门收到后把处理结果回信这个写信的人。https就是加密的信件,比如谍战片里的特工,特工给上级写的信都是用的暗语,即使信件传递过程有人拆开了信,也是看不懂信中的暗语的。在实际web的通信过程中,http和https传递的都是具有特定格式的文本信息,浏览器发起一个请求后,服务器端会做出响应把操作结果反馈给浏览器端。这个响应可能是查询数据、删除数据或者新增数据。而服务器会返回浏览器的数据通常是可以直接渲染的html和css或是可以被间接渲染的json、xml等。
二、Flask安装和调试
2.1Flask安装
首选在pytcharm里建一个python项目,然后通过命令行切换到该项目的虚拟环境。这里如何安装和使用虚拟环境参考《Anaconda的安装和使用》,如何正确使用PyCharm创建python参考《PyCharm新手入门》。
在虚拟环境输入
pip install Flask
2.2Flask调试
1. 在项目中创建一个app.py的文件。
代码如下:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
usr='老王';
print(f'{usr}已经创建好了第一个flask应用!');
return 'Hello, World!'
if __name__ == '__main__':
app.run(debug=True)
2. 设置一下flask项目的调试环境
3. 调试报错
配置好调试环境,打一个断点如下图,然后用快捷键【shift+F9】启动调试。
调试启动后,可以看到控制台给出一个访问地址http://127.0.0.1:5000。复制这个url地址在浏览器里打开。
浏览器打开后,如果app.py这个程序进入调试状态,按F8可以进入分步调试了。这意味着你可以正常调试flask应用了,当完成调试后,你在浏览器看到“Hello, World!”。这里恭喜你,你已经很顺利的配置环境,可以进入开发的阶段了。
然而事情的实际进展不会这么顺利。你可能会遇到环境报错,就像我遇到的情况。
刚一点击shift+F9就报错
[Errno 2] No such file or directory
经查网上查找资料,发现最后问题出在安装flask版本的问题上,把flask版本调整为2.0,3就可以解决问题。查看flask版本
pip show flask
发现flask版本是3.0.2,。重新安装flask
pip uninstall flask
pip install flask==2.0.3
调整版本后重新再次启动,不再报错,然后再次shift+F9启动调试,这次没有报错,但是调试启动后进入helpers.py ,再点击F8,继续调试报以下错误:
d:\conda_envs\pycharm\python.exe "D:/Program Files/PyCharm Community Edition 2023.2.3/plugins/python-ce/helpers/pydev/pydevd.py" --multiprocess --qt-support=auto --client 127.0.0.1 --port 3269 --file D:\python_workspace\pythonProject\app.py
已连接到 pydev 调试器(内部版本号 232.10072.31)Traceback (most recent call last):
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "d:\conda_envs\pycharm\lib\site-packages\flask\__init__.py", line 7, in <module>
from .app import Flask as Flask
File "d:\conda_envs\pycharm\lib\site-packages\flask\app.py", line 28, in <module>
from . import cli
File "d:\conda_envs\pycharm\lib\site-packages\flask\cli.py", line 18, in <module>
from .helpers import get_debug_flag
File "d:\conda_envs\pycharm\lib\site-packages\flask\helpers.py", line 16, in <module>
from werkzeug.urls import url_quote
ImportError: cannot import name 'url_quote' from 'werkzeug.urls' (d:\conda_envs\pycharm\lib\site-packages\werkzeug\urls.py)
python-BaseException
经上网查找问题,发现是werkzeug的版本仍然有问题,因为werkzeug是在安装flask时同时关联安装的。我们虽然重新安装了flask,但是werkzeug仍然是旧版本,于是重新安装werkzeug
pip uninstall werkzeug
pip install werkzeug==2.0.3
重新调试程序,shift+F9,F8。一切正常。这里分享一个经验给大家,在我们运行python开源项目的时候,包括大模型应用像stable diffusion、llama等,我们遇到的问题80%甚至是98%都是因为安装的库文件版本有问题。所以安装python库的时候最好搞清楚库的版本,否则你会遇到数不尽的麻烦。
二、路由和视图函数
在Flask中,路由由@app.route()装饰器定义,视图函数是处理请求并返回响应的函数。
@app.route('/user/<username>')
def show_user_profile(username):
# 通过URL中的参数访问用户信息
return f'User {username}'
@app.route('/post/<int:post_id>')
def show_post(post_id):
# 通过URL中的参数访问帖子信息,确保参数是整数类型
return f'Post {post_id}'
三、蓝图:
在 Flask 中,通常将不同的服务请求(即不同的路由和视图函数)组织在一个 Python 文件中是可行的,尤其是在小型应用或者学习阶段。然而,对于更大的应用或更好的代码组织,你可能希望将不同的服务请求拆分到不同的模块或蓝图中。
以下是一些组织服务请求的一般建议:
1.单一文件应用:
在小型应用中,将所有的服务请求都写在一个文件中是可以的,这样简单明了。例如:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'Home Page'
@app.route('/about')
def about():
return 'About Page'
if __name__ == '__main__':
app.run(debug=True)
2.模块化组织:
将相关的服务请求分组到不同的模块中,例如 views.py:
# views.py
from flask import Blueprint
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def home():
return 'Home Page'
@main_bp.route('/about')
def about():
return 'About Page'
然后在主应用中导入并注册这个蓝图:
3.蓝图
请求组织到不同的蓝图中。蓝图是一种更高级别的组织方式,用于将应用拆分为可维护的模块。例如:
# main_blueprint.py
from flask import Blueprint
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def home():
return 'Home Page'
@main_bp.route('/about')
def about():
return 'About Page'
主应用
# main_blueprint.py
from flask import Blueprint
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def home():
return 'Home Page'
@main_bp.route('/about')
def about():
return 'About Page'
这些都是一些通用的组织代码的方式,具体选择取决于你的应用规模和组织结构。在项目变得更大时,使用模块化的方式可以更好地保持代码的可维护性。
四、表单处理:
Flask可以轻松处理表单提交。使用request对象从POST请求中获取表单数据,或使用flask-wtf等扩展库来简化表单处理。
from flask import Flask, render_template, request
@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
# 处理表单提交的数据
return f'Username: {username}, Password: {password}'
return render_template('login.html')
五、Jinqa模版
在 Flask 中,你可以使用模板引擎来实现动态页面。模板引擎允许你在 HTML 文件中嵌入动态内容,从而根据不同的请求动态生成页面。Flask 默认使用 Jinja2 模板引擎,它提供了灵活的语法和功能,方便在 HTML 中插入动态内容。
1.安装 Jinja2:
如果你是在新的虚拟环境中,你需要安装 Jinja2:
pip install Jinja2
2.创建 Flask 应用:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
# 传递动态数据到模板
user = {'username': 'John', 'age': 25}
return render_template('home.html', user=user)
if __name__ == '__main__':
app.run(debug=True)
3.创建模板文件:
在你的项目目录下创建一个名为 templates 的文件夹,然后在该文件夹中创建 home.html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Page</title>
</head>
<body>
<h1>Welcome, {{ user.username }}!</h1>
<p>Your age is {{ user.age }}.</p>
</body>
</html>
在这个例子中,{{ user.username }} 和 {{ user.age }} 是模板中的变量,它们将在运行时由 Flask 填充为相应的值。
六、操作数据库
1.sqlite3模块
SQLite 是一个自包含、无服务器、零配置的 SQL 数据库引擎。它是 Python 标准库的一部分,所以在大多数情况下,你不需要手动安装 SQLite 数据库,因为它已经包含在 Python 的 sqlite3 模块中。
在 Python 中,你可以使用标准库中的 sqlite3 模块来访问 SQLite 数据库:
import sqlite3
# 连接到 SQLite 数据库(如果数据库不存在,会自动创建)
conn = sqlite3.connect('example.db')
# 创建一个游标对象
cursor = conn.cursor()
# 执行 SQL 语句
cursor.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)')
# 插入数据
cursor.execute('INSERT INTO users (name, age) VALUES (?, ?)', ('Alice', 30))
# 提交事务
conn.commit()
# 查询数据
cursor.execute('SELECT * FROM users')
print(cursor.fetchall())
# 关闭连接
conn.close()
这个示例展示了如何使用 Python 的 sqlite3 模块来创建表、插入数据和查询数据。你可以直接在你的 Python 环境中运行这个代码来测试 SQLite 数据库的基本功能。
2.使用SQLAlchemy模块访问数据库
除了python自带的标准sqlite3模块,还可以通过SQLAlchemy 来处理和数据库交互,不同的是,这个模块除了sqlite还可以访问mysql等其他数据库。
使用SQLAlchemy操作数据库的步骤
安装依赖
pip install Flask SQLAlchemy
创建 Flask 应用
1. 项目结构
/flask_app
├── app.py
├── models.py
└── templates
└── index.html
2.models.py - 定义数据库模型
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False)
age = db.Column(db.Integer, nullable=False)
def __repr__(self):
return f'<User {self.name}>'
3 .app.py - 主应用文件
from flask import Flask, request, jsonify, render_template
from models import db, User
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
@app.route('/')
def index():
users = User.query.all()
return render_template('index.html', users=users)
@app.route('/user', methods=['POST'])
def create_user():
data = request.get_json()
new_user = User(name=data['name'], age=data['age'])
db.session.add(new_user)
db.session.commit()
return jsonify({'message': 'User created'}), 201
@app.route('/user/<int:id>', methods=['GET'])
def get_user(id):
user = User.query.get_or_404(id)
return jsonify({'id': user.id, 'name': user.name, 'age': user.age})
@app.route('/user/<int:id>', methods=['PUT'])
def update_user(id):
data = request.get_json()
user = User.query.get_or_404(id)
user.name = data.get('name', user.name)
user.age = data.get('age', user.age)
db.session.commit()
return jsonify({'message': 'User updated'})
@app.route('/user/<int:id>', methods=['DELETE'])
def delete_user(id):
user = User.query.get_or_404(id)
db.session.delete(user)
db.session.commit()
return jsonify({'message': 'User deleted'})
if __name__ == '__main__':
with app.app_context():
db.create_all()
app.run(debug=True)
4 .templates/index.html - 用于显示用户列表的简单 HTML 模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>User List</title>
</head>
<body>
<h1>User List</h1>
<ul>
{% for user in users %}
<li>{{ user.name }} ({{ user.age }} years old)</li>
{% endfor %}
</ul>
</body>
</html>