当前位置: 首页 > news >正文

Python之Flask开发框架(第二篇) — 模板、表单与数据库

在上一篇教程中,我们掌握了 Flask 的基础知识,包括安装、第一个应用、路由和视图函数。本篇将带领大家进入 Flask 开发的更核心领域:模板渲染表单处理数据库操作。通过这些内容,你将能够构建出功能完整、交互友好且具备数据持久化能力的 Web 应用。


1. 模板渲染

在实际项目中,我们通常不会在视图函数中直接返回 HTML 字符串,而是将 HTML 代码放在独立的模板文件中,并通过模板引擎动态填充数据。Flask 默认使用Jinja2模板引擎。

1.1 基本模板语法

首先,在项目根目录下创建templates文件夹,用于存放所有模板文件。创建一个简单的模板index.html

<!DOCTYPEhtml><html><head><title>{{ title }}</title></head><body><h1>Hello, {{ name }}!</h1></body></html>

在视图函数中,使用render_template函数渲染模板并传递参数:

fromflaskimportrender_template@app.route('/')defindex():returnrender_template('index.html',title='Home',name='Alice')

Jinja2 支持多种语法:

  • 变量{{ variable }}
  • 控制结构
    {% if user %} <p>Hello, {{ user }}</p> {% else %} <p>Hello, Guest</p> {% endif %} {% for item in items %} <li>{{ item }}</li> {% endfor %}
  • 过滤器:通过|对变量进行格式化,如{{ name|upper }}{{ date|datetime }}(需自定义)。
  • :类似函数,可复用模板片段:
    {% macro input(name, value='', type='text') %} <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> {% endmacro %}

1.2 模板继承

模板继承是 Jinja2 最强大的功能之一,可以避免重复代码。定义一个基础模板base.html

<!DOCTYPEhtml><html><head><title>{% block title %}{% endblock %} - My App</title></head><body><header><h1>My App</h1></header><main>{% block content %}{% endblock %}</main><footer><p>&copy;2023</p></footer></body></html>

子模板通过extends继承,并填充block

{% extends "base.html" %} {% block title %}Home{% endblock %} {% block content %}<p>Welcome to the homepage!</p>{% endblock %}

1.3 静态文件管理

静态文件(CSS、JS、图片)应放在static文件夹中。在模板中,使用url_for('static', filename='style.css')生成正确路径:

<linkrel="stylesheet"href="{{ url_for('static', filename='style.css') }}">

2. 表单处理

表单是用户与 Web 应用交互的主要方式。Flask 本身提供了基础的请求数据处理,但推荐使用Flask-WTF扩展来简化表单创建、验证和 CSRF 保护。

2.1 安装 Flask-WTF

pipinstallflask-wtf

2.2 定义表单类

表单类继承自FlaskForm,字段类型由 WTForms 提供。创建一个简单的登录表单:

fromflask_wtfimportFlaskFormfromwtformsimportStringField,PasswordField,SubmitFieldfromwtforms.validatorsimportDataRequired,Email,LengthclassLoginForm(FlaskForm):email=StringField('Email',validators=[DataRequired(),Email()])password=PasswordField('Password',validators=[DataRequired(),Length(min=6)])submit=SubmitField('Login')

2.3 在视图中使用表单

在视图函数中创建表单实例,并检查validate_on_submit()来处理提交。

fromflaskimportrender_template,redirect,url_for@app.route('/login',methods=['GET','POST'])deflogin():form=LoginForm()ifform.validate_on_submit():# 表单验证通过,处理登录逻辑email=form.email.data password=form.password.data# 实际开发中应验证数据库中的用户returnredirect(url_for('index'))returnrender_template('login.html',form=form)

2.4 在模板中渲染表单

Jinja2 可以方便地渲染表单字段和错误信息:

{% extends "base.html" %} {% block content %}<formmethod="POST"action="">{{ form.hidden_tag() }}<!-- 生成 CSRF token --><div>{{ form.email.label }}<br>{{ form.email(size=32) }}<br>{% for error in form.email.errors %}<spanstyle="color:red;">[{{ error }}]</span>{% endfor %}</div><div>{{ form.password.label }}<br>{{ form.password(size=32) }}<br>{% for error in form.password.errors %}<spanstyle="color:red;">[{{ error }}]</span>{% endfor %}</div><div>{{ form.submit() }}</div></form>{% endblock %}

2.5 CSRF 保护

Flask-WTF 默认启用 CSRF 保护。你需要在应用配置中设置一个密钥:

app.config['SECRET_KEY']='your-secret-key-here'

表单中的{{ form.hidden_tag() }}会生成一个隐藏字段,包含 CSRF 令牌。


3. 数据库操作

Flask 本身不绑定数据库,但推荐使用Flask-SQLAlchemy作为 ORM 工具,它简化了数据库操作。我们还会使用Flask-Migrate来管理数据库迁移。

3.1 安装扩展

pipinstallflask-sqlalchemy flask-migrate

3.2 配置数据库

在应用配置中设置数据库 URI(以 SQLite 为例):

app.config['SQLALCHEMY_DATABASE_URI']='sqlite:///app.db'app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False

初始化 SQLAlchemy 和 Migrate:

fromflask_sqlalchemyimportSQLAlchemyfromflask_migrateimportMigrate db=SQLAlchemy(app)migrate=Migrate(app,db)

3.3 定义模型

模型类继承自db.Model,每个类对应一张数据库表。例如,创建一个用户模型:

classUser(db.Model):id=db.Column(db.Integer,primary_key=True)username=db.Column(db.String(64),unique=True,nullable=False)email=db.Column(db.String(120),unique=True,nullable=False)password_hash=db.Column(db.String(128))def__repr__(self):returnf'<User{self.username}>'

3.4 数据库迁移

使用 Flask-Migrate 可以自动化地生成数据库迁移脚本,避免手动操作。

初始化迁移仓库(只需一次):

flask db init

生成迁移脚本(当模型改变时):

flask db migrate-m"create user table"

应用迁移到数据库:

flask db upgrade

3.5 基本 CRUD 操作

在视图函数中操作数据库。示例:注册用户

fromwerkzeug.securityimportgenerate_password_hash@app.route('/register',methods=['GET','POST'])defregister():form=RegistrationForm()ifform.validate_on_submit():# 检查用户名或邮箱是否已存在user=User.query.filter_by(username=form.username.data).first()ifuser:flash('Username already exists','danger')returnredirect(url_for('register'))# 创建新用户new_user=User(username=form.username.data,email=form.email.data,password_hash=generate_password_hash(form.password.data))db.session.add(new_user)db.session.commit()flash('Registration successful!','success')returnredirect(url_for('login'))returnrender_template('register.html',form=form)

常用查询方法:

  • 查询所有:User.query.all()
  • 按条件查询:User.query.filter_by(username='alice').first()
  • 获取主键:User.query.get(1)
  • 复杂过滤:User.query.filter(User.email.endswith('@example.com')).all()
  • 分页:User.query.paginate(page=1, per_page=20)

3.6 关系映射

定义一对多关系。例如,一个用户可以有多个文章:

classUser(db.Model):# ...posts=db.relationship('Post',backref='author',lazy='dynamic')classPost(db.Model):id=db.Column(db.Integer,primary_key=True)title=db.Column(db.String(100))body=db.Column(db.Text)user_id=db.Column(db.Integer,db.ForeignKey('user.id'))
  • db.relationship定义在 User 模型上,表示从 User 到 Post 的关系。
  • backref='author'使得可以从 Post 对象直接访问post.author获取作者。
  • lazy='dynamic'表示user.posts返回一个查询对象,而不是立即加载所有文章。

多对多关系需要借助关联表。例如,用户和角色:

# 关联表roles_users=db.Table('roles_users',db.Column('user_id',db.Integer,db.ForeignKey('user.id')),db.Column('role_id',db.Integer,db.ForeignKey('role.id')))classRole(db.Model):id=db.Column(db.Integer,primary_key=True)name=db.Column(db.String(50),unique=True)users=db.relationship('User',secondary=roles_users,backref='roles')

4. 蓝图(Blueprint)

当应用规模变大时,将所有路由放在一个文件中会变得混乱。Flask 提供了蓝图来模块化路由和视图。

4.1 定义蓝图

创建一个auth蓝图,处理认证相关路由:

# auth.pyfromflaskimportBlueprint,render_template auth_bp=Blueprint('auth',__name__,url_prefix='/auth')@auth_bp.route('/login')deflogin():returnrender_template('auth/login.html')

4.2 注册蓝图

在应用工厂中注册蓝图:

defcreate_app():app=Flask(__name__)# ...from.authimportauth_bp app.register_blueprint(auth_bp)returnapp

4.3 蓝图中的 url_for

在模板或视图中,使用带蓝图名的url_for

url_for('auth.login')# 生成 /auth/login

5. 错误处理

Flask 允许自定义错误页面,提升用户体验。

5.1 使用 errorhandler 装饰器

@app.errorhandler(404)defpage_not_found(e):returnrender_template('404.html'),404@app.errorhandler(500)definternal_server_error(e):returnrender_template('500.html'),500

5.2 在蓝图中自定义错误

蓝图也可以有自己的错误处理器,但作用范围仅限于该蓝图下的路由。


总结

在本篇教程中,我们学习了:

  1. 模板渲染:使用 Jinja2 模板引擎,包括继承、过滤器、静态文件管理。
  2. 表单处理:通过 Flask-WTF 定义表单类、验证数据、CSRF 保护。
  3. 数据库操作:使用 Flask-SQLAlchemy 定义模型、执行 CRUD、管理关系,并利用 Flask-Migrate 进行数据库版本控制。
  4. 蓝图:将应用模块化,便于组织和扩展。
  5. 错误处理:自定义错误页面,提升用户友好度。

掌握了这些内容后,你已经具备了构建完整 Web 应用的能力。在第三篇(也是最后一篇)教程中,我们将深入探讨Flask 的高级主题,包括:中间件与扩展项目部署,并给出一个综合示例,将所学知识串联起来。

请继续关注第三篇,我们将在那里完成 Flask 学习的最后一块拼图。如果你对第二篇有任何疑问,欢迎随时提出。

http://www.cnnetsun.cn/news/1614810.html

相关文章:

  • 别再到处找模型了!手把手教你用Xinference+Docker本地部署私有LLaMA模型(附完整目录结构)
  • 利用Opencv+Mediapipe实现实时头部姿态追踪与可视化
  • 车载Android Auto兼容性开发全链路(车规级Java SDK集成手册)
  • FeignClient调用接口参数为null?可能是这个阿里规范在作怪
  • ESP32 BLE实战:5分钟搞定自定义GATT服务(附完整代码)
  • 多设备协同登录解决方案:WeChatPad无缝登录技术全解析
  • VBA循环到底用For、Do While还是Do Until?看完这篇别再傻傻分不清
  • OpenCore Legacy Patcher技术突破:深度解构非官方macOS升级的终极方案
  • 开发慢、运维难?JVS 低代码重塑企业数字化交付效率
  • CodecWSN:面向WSN的8字节二进制编解码协议解析
  • 2026年山东潍坊美都西瓜采购指南:如何挑选靠谱代办?
  • 为什么你的密码总被破解?聊聊哈希算法在密码存储中的那些坑
  • 百度网盘解析工具:突破下载限制的高效解决方案与极速体验
  • 解码汽车ECU的“健康档案”:剖析吉利Basetech五大运行周期计数器(OCC)的协同诊断逻辑
  • 5分钟搞懂卷积:从数学公式到PyTorch实战(附代码)
  • 基于JAVA实现modbus rtu通信(二):数据类型转换与读写实战
  • 保姆级教程:在Qt 5.14.2的QWidget里用PCL 1.8.1显示并实时调色点云(附完整.pro配置)
  • DS4Windows手柄适配工具全解析:从安装到高级配置的完美指南
  • 告别docker.io!Podman切换国内镜像源提升10倍拉取速度
  • 双向全桥隔离DC-DC变换器(DAB)的调制与控制优化策略
  • 复值神经网络(ComplexNN):从理论到开源实现,解锁信号处理与LLM新潜力
  • DDRNet实战:如何在Cityscapes数据集上复现77.4% mIoU的实时语义分割效果
  • CV工程师必看:ResNet变体演进史——从Kaiming原始论文到DenseNet的20个关键设计细节
  • ARMv8虚拟化性能优化指南:TLB的ASID和VMID到底怎么用?
  • 告别重复劳动:用快马ai一键生成vmware workstation高效运维脚本
  • JavaWeb邮箱验证避坑指南:163/QQ邮箱SMTP配置常见问题解决方案
  • 【深度解析】用 Superpowers 改造 AI 编码代理:从“快手实习生”到“有流程的工程师”
  • markitdown:智能转换PPT到Markdown的效率工具,实现内容结构化处理
  • 3步解锁B站缓存自由:让m4s视频转MP4从此零门槛
  • 无需公网 IP!手把手教你把内网 Serv-U 文件服务映射到外网,远程访问超简单