flask ApI快速上手

引言

Flask是Python Web开发领域最受欢迎的微框架之一,其轻量、灵活和易于扩展的特性。

Flask 简介

2.1 什么是Flask

Flask是一个轻量级的Python Web应用框架,Flask被称为"微框架",因为它保持核心简单但可扩展,不强制依赖特定的库或工具,给予开发者极大的灵活性和控制力。

Flask的主要特点包括:

轻量且高效:核心简洁,启动迅速,资源占用低

灵活性:不强制特定项目结构或组件选择

易于学习:API设计直观,学习曲线平缓

可扩展性:通过丰富的扩展生态系统增强功能

强大的路由系统:支持URL变量和HTTP方法

内置开发服务器:便于本地测试和开发

RESTful支持:轻松构建符合REST规范的API

2.2 Flask

安装Flask

使用pip安装Flask非常简单:

java 复制代码
pip install flask

建议在虚拟环境中安装Flask,以避免依赖冲突(建议使用miniconda):

java 复制代码
# 创建虚拟环境
python -m venv venv

# 激活虚拟环境(Windows)
venv\Scripts\activate

# 激活虚拟环境(Linux/Mac)
source venv/bin/activate

安装Flask

java 复制代码
pip install flask
验证安装:
python -c "import flask; print(flask.__version__)"

Flask 基础知识

第一个Flask应用

创建一个最简单的Flask应用只需几行代码:

java 复制代码
from flask import Flask

# 创建Flask应用实例
app = Flask(__name__)

# 定义路由和视图函数
@app.route('/')
def hello_world():
    return 'Hello, World!'

启动应用

if name == 'main ':

app.run(debug=True)

将上述代码保存为app.py并运行:

java 复制代码
python app.py

打开浏览器访问http://127.0.0.1:5000/即可看到"Hello, World!"消息。

应用实例

Flask应用的核心是Flask类 的实例,通常命名为app:

java 复制代码
app = Flask(__name__)

# 参数__name__是Python的特殊变量,它会传递当前模块的名称给Flask。这有助于Flask找到资源文件的位置。

路由系统

路由是将URL映射到视图函数的机制。Flask使用装饰器来定义路由:

java 复制代码
@app.route('/user/<username>')
def show_user_profile(username):
    return f'User {username}'

Flask支持在URL中包含变量,类型可以是:

字符串(默认):

整数:int:post_id

浮点数:float:score

路径:path:subpath

UUID:uuid:id

示例:

java 复制代码
@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'Post {post_id}'

路由可以限定接受的HTTP方法:

java 复制代码
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 处理表单提交
        return '处理登录'
    else:
        # 显示登录表单
        return '显示登录表单'

视图函数

视图函数是处理请求并返回响应的Python函数。视图函数可以返回:

字符串:直接显示为HTML

HTML模板渲染结果

JSON响应

重定向

自定义响应对象

示例:

java 复制代码
from flask import render_template, jsonify, redirect, url_for

@app.route('/template')
def template_example():
    return render_template('example.html', name='Flask')

@app.route('/api/data')
def api_data():
    return jsonify({"name": "Flask", "type": "framework"})

@app.route('/redirect')
def redirect_example():
    return redirect(url_for('hello_world'))

请求对象

Flask通过request对象提供对客户端请求数据的访问:

python 复制代码
from flask import request

@app.route('/submit', methods=['POST'])
def submit():
    # 获取表单数据
    username = request.form.get('username')
    # 获取URL参数
    page = request.args.get('page', 1, type=int)
    # 获取JSON数据
    data = request.get_json()
    # 获取文件
    file = request.files.get('upload')
    
    return f'Received: {username}'

3.6 响应对象

视图函数可以返回一个元组来设置响应的状态码和头信息:

python 复制代码
@app.route('/response')
def custom_response():
    return 'Custom response', 201, {'X-Custom-Header': 'value'}

也可以使用make_response函数创建自定义响应:

python 复制代码
from flask import make_response

@app.route('/cookie')
def set_cookie():
    resp = make_response('Cookie设置成功')
    resp.set_cookie('username', 'flask_user')
    return resp

模板系统

Flask使用Jinja2作为默认的模板引擎,它功能强大且易于使用。

Jinja2模板基础

Jinja2模板是包含静态内容和动态内容占位符的文件。默认情况下,Flask在应用的templates目录中查找模板。

一个基本的HTML模板示例(templates/index.html):

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    <h1>Hello, {{ name }}!</h1>
    {% if messages %}
    <ul>
        {% for message in messages %}
        <li>{{ message }}</li>
        {% endfor %}
    </ul>
    {% else %}
    <p>No messages.</p>
    {% endif %}
</body>
</html>

在视图中渲染该模板:

python 复制代码
@app.route('/')
def index():
    return render_template('index.html', 
                          title='Flask Template',
                          name='User',
                          messages=['Message 1', 'Message 2'])

模板语法

Jinja2模板支持三种主要的语法结构:

python 复制代码
变量:{{ variable }}
控制结构:{% if condition %} ... {% endif %}
注释:{# This is a comment #}

4.2.1 变量与过滤器

变量可以通过过滤器进行转换:

python 复制代码
{{ name|capitalize }}
{{ text|truncate(100) }}
{{ data|tojson }}

常用的过滤器:

python 复制代码
safe: 标记内容为安全,不进行转义
escape: HTML转义
capitalize: 首字母大写
lower/upper: 转换大小写
trim: 去除首尾空白
striptags: 移除HTML标签
default: 提供默认值

4.2.2 控制结构

条件语句:

python 复制代码
{% if user.is_authenticated %}
    <a href="{{ url_for('logout') }}">Logout</a>
{% else %}
    <a href="{{ url_for('login') }}">Login</a>
{% endif %}

循环:

python 复制代码
<ul>
{% for item in items %}
    <li>{{ loop.index }} - {{ item.name }}</li>
{% else %}
    <li>No items found.</li>
{% endfor %}
</ul>

4.3 模板继承

Jinja2支持模板继承,这是一种强大的组织模板的方式。

基础模板(base.html):

python 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Default Title{% endblock %}</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    {% block styles %}{% endblock %}
</head>
<body>
    <header>
        <nav>{% block nav %}{% endblock %}</nav>
    </header>
    
    <main>
        {% block content %}{% endblock %}
    </main>
    
    <footer>
        {% block footer %}© 2023 Flask应用{% endblock %}
    </footer>
    
    {% block scripts %}{% endblock %}
</body>
</html>

子模板(page.html):

python 复制代码
{% extends "base.html" %}

{% block title %}页面标题{% endblock %}

{% block content %}
<h1>页面内容</h1>
<p>这是页面的具体内容。</p>
{% endblock %}

4.4 静态文件

Flask自动为静态文件添加路由。默认情况下,静态文件应放在应用的static目录中。

在模板中引用静态文件:

python 复制代码
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<img src="{{ url_for('static', filename='images/logo.png') }}">
<script src="{{ url_for('static', filename='js/script.js') }}"></script>

4.5 URL生成

使用url_for()函数动态生成URL,避免硬编码:

python 复制代码
<a href="{{ url_for('index') }}">首页</a>
<a href="{{ url_for('user_profile', username='john') }}">用户资料</a>
<a href="{{ url_for('static', filename='style.css') }}">样式表</a>
  1. 表单处理
    Web应用几乎都需要处理用户输入的表单数据。Flask提供了多种方式处理表单提交。

5.1 基本表单处理

最简单的表单处理方式是直接使用Flask的request对象:

python 复制代码
from flask import request, redirect, url_for, render_template

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        
        # 验证用户名和密码
        if username == 'admin' and password == 'secret':
            return redirect(url_for('dashboard'))
        else:
            error = '无效的用户名或密码'
            return render_template('login.html', error=error)
    
    # GET请求显示表单
    return render_template('login.html')
python 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>登录</title>
</head>
<body>
    <h1>登录</h1>
    {% if error %}
    <p style="color: red;">{{ error }}</p>
    {% endif %}
    
    <form method="post">
        <div>
            <label>用户名:</label>
            <input type="text" name="username" required>
        </div>
        <div>
            <label>密码:</label>
            <input type="password" name="password" required>
        </div>
        <button type="submit">登录</button>
    </form>
</body>
</html>

5.2 使用Flask-WTF扩展

对于复杂表单,推荐使用Flask-WTF扩展,它结合了WTForms库,提供了表单验证、CSRF保护等功能。

安装Flask-WTF:

python 复制代码
pip install flask-wtf

配置应用:

python 复制代码
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'  # 用于CSRF保护

定义表单类:

python 复制代码
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, Length

class LoginForm(FlaskForm):
    email = StringField('邮箱', validators=[DataRequired(), Email()])
    password = PasswordField('密码', validators=[DataRequired(), Length(min=6)])
    submit = SubmitField('登录')

在视图中使用表单:

python 复制代码
@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    
    if form.validate_on_submit():
        # 表单验证通过
        email = form.email.data
        password = form.password.data
        
        # 处理登录逻辑
        return redirect(url_for('dashboard'))
    
    return render_template('login_wtf.html', form=form)

带有WTForms的模板(login_wtf.html):

python 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>登录</title>
</head>
<body>
    <h1>登录</h1>
    
    <form method="post">
        {{ form.hidden_tag() }}
        <div>
            {{ form.email.label }}
            {{ form.email }}
            {% if form.email.errors %}
            <ul>
                {% for error in form.email.errors %}
                <li>{{ error }}</li>
                {% endfor %}
            </ul>
            {% endif %}
        </div>
        <div>
            {{ form.password.label }}
            {{ form.password }}
            {% if form.password.errors %}
            <ul>
                {% for error in form.password.errors %}
                <li>{{ error }}</li>
                {% endfor %}
            </ul>
            {% endif %}
        </div>
        {{ form.submit }}
    </form>
</body>
</html>

文件上传

处理文件上传需要在表单中添加enctype="multipart/form-data"属性:

python 复制代码
<form method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <button type="submit">上传</button>
</form>

在Flask中处理上传文件:

python 复制代码
from werkzeug.utils import secure_filename
import os

UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # 检查是否有文件部分
        if 'file' not in request.files:
            return '没有文件部分'
            
        file = request.files['file']
        
        # 如果用户未选择文件,浏览器会提交一个没有文件名的空部分
        if file.filename == '':
            return '未选择文件'
            
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return f'文件 {filename} 上传成功'
    
    return '''
    <!doctype html>
    <title>上传文件</title>
    <h1>上传文件</h1>
    <form method="post" enctype="multipart/form-data">
      <input type="file" name="file">
      <input type="submit" value="上传">
    </form>
    '''

5.4 表单验证

WTForms提供了丰富的验证器:

DataRequired:字段不能为空

Email:必须是有效的电子邮件地址

Length:字符串长度限制

NumberRange:数值范围限制

EqualTo:字段必须与另一个字段值相等(如密码确认)

URL:必须是有效的URL

Regexp:必须匹配正则表达式

自定义验证示例:

python 复制代码
from wtforms import ValidationError

class RegistrationForm(FlaskForm):
    username = StringField('用户名', validators=[DataRequired(), Length(min=4, max=20)])
    email = StringField('邮箱', validators=[DataRequired(), Email()])
    password = PasswordField('密码', validators=[DataRequired(), Length(min=6)])
    confirm_password = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('注册')
    
    def validate_username(self, username):
        # 检查用户名是否已存在
        if username.data == 'admin':
            raise ValidationError('该用户名已被使用,请选择其他用户名。')

数据库集成

Flask本身不包含数据库抽象层,但可以与各种数据库解决方案集成。最常用的是SQLAlchemy ORM通过Flask-SQLAlchemy扩展。

安装:

python 复制代码
pip install flask-sqlalchemy

基本配置:

python 复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

数据库URL格式因数据库类型而异:

python 复制代码
SQLite: sqlite:///site.db
MySQL: mysql://username:password@localhost/db_name
PostgreSQL: postgresql://username:password@localhost/db_name

定义模型

使用SQLAlchemy定义数据库模型(表):

python 复制代码
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password = db.Column(db.String(60), nullable=False)
    
    # 一对多关系
    posts = db.relationship('Post', backref='author', lazy=True)
    
    def __repr__(self):
        return f"User('{self.username}', '{self.email}')"

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)
    date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    
    # 外键
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    
    def __repr__(self):
        return f"Post('{self.title}', '{self.date_posted}')"

6.3 创建和迁移数据库

创建数据库表:

python 复制代码
# 在Python交互式shell中
from app import db
db.create_all()

对于更复杂的迁移,可以使用Flask-Migrate扩展(基于Alembic):

python 复制代码
pip install flask-migrate

配置Flask-Migrate:

python 复制代码
from flask_migrate import Migrate

migrate = Migrate(app, db)

然后可以使用命令行管理迁移:

python 复制代码
flask db init      # 初始化迁移仓库
flask db migrate   # 创建迁移脚本
flask db upgrade   # 应用迁移到数据库

基本CRUD操作

创建记录

python 复制代码
@app.route('/add_user', methods=['POST'])
def add_user():
    username = request.form.get('username')
    email = request.form.get('email')
    password = request.form.get('password')
    
    user = User(username=username, email=email, password=password)
    db.session.add(user)
    db.session.commit()
    
    return f'用户 {username} 已添加'

查询记录

python 复制代码
@app.route('/users')
def get_users():
    users = User.query.all()
    return render_template('users.html', users=users)

@app.route('/user/<int:user_id>')
def get_user(user_id):
    user = User.query.get_or_404(user_id)
    return render_template('user.html', user=user)

常用查询方法:

python 复制代码
# 获取所有记录
User.query.all()

# 获取指定ID的记录
User.query.get(1)
User.query.get_or_404(1)  # ID不存在时返回404错误

# 条件查询
User.query.filter_by(username='john').first()
User.query.filter(User.email.endswith('@example.com')).all()

# 排序
User.query.order_by(User.username).all()

# 限制结果数量
User.query.limit(10).all()

# 分页
users = User.query.paginate(page=2, per_page=20)
for user in users.items:
    print(user.username)

更新记录

python 复制代码
@app.route('/update_user/<int:user_id>', methods=['POST'])
def update_user(user_id):
    user = User.query.get_or_404(user_id)
    
    user.username = request.form.get('username', user.username)
    user.email = request.form.get('email', user.email)
    
    db.session.commit()
    
    return f'用户 {user.username} 已更新'
python 复制代码
删除记录
@app.route('/delete_user/<int:user_id>', methods=['POST'])
def delete_user(user_id):
    user = User.query.get_or_404(user_id)
    
    db.session.delete(user)
    db.session.commit()
    
    return f'用户 {user.username} 已删除'

对于中大型Flask应用,推荐以下目录结构:

python 复制代码
myapp/
├── app/
│   ├── __init__.py          # 应用工厂
│   ├── models/              # 数据库模型
│   │   ├── __init__.py
│   │   ├── user.py
│   │   └── post.py
│   ├── views/               # 视图函数和蓝图
│   │   ├── __init__.py
│   │   ├── main.py
│   │   ├── auth.py
│   │   └── api.py
│   ├── forms/               # 表单类
│   │   ├── __init__.py
│   │   ├── auth.py
│   │   └── main.py
│   ├── static/              # 静态文件
│   │   ├── css/
│   │   ├── js/
│   │   └── img/
│   ├── templates/           # HTML模板
│   │   ├── base.html
│   │   ├── main/
│   │   ├── auth/
│   │   └── errors/
│   └── utils/               # 工具函数
│       ├── __init__.py
│       └── helpers.py
├── migrations/              # 数据库迁移
├── tests/                   # 测试用例
│   ├── __init__.py
│   ├── test_user.py
│   └── test_api.py
├── venv/                    # 虚拟环境
├── config.py                # 配置文件
├── requirements.txt         # 依赖包列表
├── run.py                   # 应用入口
└── README.md                # 项目说明
相关推荐
浩瀚之水_csdn2 小时前
【框架】flask路由深度解析
后端·python·flask
Sagittarius_A*2 小时前
图像去雾:从直方图增强到暗通道先验【计算机视觉】
图像处理·人工智能·python·opencv·计算机视觉·图像去雾·暗通道先验
zach01272 小时前
神经符号系统驱动的宠物健康监测范式革命:基于安庆大观区多模态数据流的GEO精准引流拓扑重构
人工智能·python·重构·宠物
LEAKSENSE2 小时前
漏液报警器白皮书:技术革新×应用实践·未来蓝图
大数据·人工智能·python
源码之屋2 小时前
毕业设计源码:python网易云音乐数据分析可视化平台 Flask+ECharts 多维度数据可视化分析 人工智能 大数据 机器学习 (建议收藏)✅
人工智能·python·信息可视化·django·毕业设计·echarts·课程设计
FL16238631292 小时前
基于yolov11+django+deepseek的交通标志识别系统带登录界面python源码+onnx模型+精美web界面
python·yolo·django
程序员敲代码吗2 小时前
使用OpenPDF实现HTML到PDF的高效转换
python·pdf·html
weixin_381856492 小时前
uiautomator2移动端结合后端接口配置通话压力测试
windows·python·pycharm·接口测试·压力测试·ui自动化测试
Lyyaoo.2 小时前
Lombok工具库
开发语言·python