本文记录了一些关于Flask的基本概念与使用方法。Flask是一个轻量级的web框架,支持前后端整合,并且可在前端中直接使用相关的python语句。支持ORM(Object Relational Mapping),很好的结合mvc模式进行开发。

依赖安装

# Flask依赖
pip install Flask
# 与数据库交互
pip install flask-sqlalchemy
# 将已有数据库导入
pip install sqlacodegen
# 注册发送邮件
pip install flask-mail
# 前端表单验证
pip install wtforms

Jinja2

Jinja2是一个Python模板引擎,它提供一种将数据和模板结合在一起,以生成动态文本的方法。它能够生成具有清晰而简洁的结构、更易读取的网页代码

它的常用使用方法有:python变量、语句直接在模板中使用或执行

使用{ { } }来包含一个变量,在render_template中通过额外的参数传递变量至定位的模板中,在该模板中可以使用{ { var } }来使用传递的变量

return render_template("admin.html", hotels=hotels, facilities=facilities)

在admin.html中,可以使用来使用hotels变量

<div class="container">
<div class="row" style="margin-top: 20px;">
<div class="col-10">
<ul class="question-ul" style="position: relative; left: 70px; top: 30px">
{% for hotel in hotels %}
<li>
<div class="hotel-main">
<div class="question-title">
<a>
{{hotel.name}}
</a>
</div>

使用{ % % }来使用python语句,例如上方的代码中想要使用python中的for循环,直接使用{ % for hotel in hotels % }即可

需要注意的是,jinja2中对于语句的使用,都需要有闭合。例如{ % if % }则需要在代码块结束之后以{ % endif % }结尾;{ % for % }则需要以{ % endfor% }结尾

更多的使用方法尚未学习🕊🕊🕊

config

配置方面,和SpringBoot很相似,支持用一个config.py文件来进行数据库、发送邮件的smtp服务器以及密钥等

SECRET_KEY = "Geo0426_xxxUniversity_xxx"

# 主机
HOSTNAME = "localhost"
# 端口
PORT = 3307
# 用户名
USERNAME = "root"
# 密码
PASSWORD = "123456"
# 数据库名称
DATABASE = "hms"
# uri
DB_URI = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"

SQLALCHEMY_DATABASE_URI = DB_URI

# 邮箱服务
MAIL_SERVER = "smtp.163.com"
MAIL_USE_SSL = True
MAIL_PORT = 465
MAIL_USERNAME = "xxx@163.com"
MAIL_PASSWORD = "xxx"
MAIL_DEFAULT_SENDER = "xxx@163.com"

app

Flask的核心(有点类似Vue的感觉),相当于一个主类,将相关的数据库、控制器(这里应该是blueprints)、配置进行管理,此外“钩子”函数(请求拦截器,上下文处理器)也定义在其中

请求拦截器

在每一个请求执行之前,都会先执行的函数。这里在请求发起之前先将浏览器中session的token取出来,如果存在token信息则表示完成了登录,可以给全局变量g.user设置信息;否则将其设置为空表示没有登录

@app.before_request
def my_before_request():
user_id = session.get("user_id")
if user_id:
user = User.query.get(user_id)
setattr(g, "user", user)
else:
setattr(g, "user", None)

上下文处理器

用来处理一些所有页面都需要进行渲染的变量,比如登录信息,使用它就可以很好配合jinja2

例如我们将用户登录后的信息用一个user变量存储

@app.context_processor
def my_context_processor():
return {"user": g.user}

它返回的是一个字典,接下里所有template中都可以使用这个键值来获取这个对象g.user

{% if user %}
<li class="nav-item">
<span class="nav-link">{{ user.username }}</span>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('auth.logout') }}">退出登录</a>
</li>
{% else %}

完整的代码如下

from flask import Flask, session, g
from ext import db, mail
from blueprints.auth import bp as auth_bp
from blueprints.users import bp as user_bp
from blueprints.hotels import bp as hotel_bp
from blueprints.rooms import bp as room_bp
from models import User
import config

app = Flask(__name__)
# 配置
app.config.from_object(config)
# 解决循环引用的问题
db.init_app(app)
# 注册蓝图
app.register_blueprint(auth_bp)
app.register_blueprint(user_bp)
app.register_blueprint(hotel_bp)
app.register_blueprint(room_bp)
mail.init_app(app)


@app.before_request
def my_before_request():
user_id = session.get("user_id")
if user_id:
user = User.query.get(user_id)
setattr(g, "user", user)
else:
setattr(g, "user", None)


# 上下文处理器,用来处理一些所有界面都需要用到的变量(可以用来对登录状态做一个保存)
@app.context_processor
def my_context_processor():
return {"user": g.user}


if __name__ == "__main__":
app.run()

models

models是Flask中ORM的核心部分,通过类定义的方式,与数据库中的表进行映射

class Facility(db.Model):
__tablename__ = 't_facility'

id = Column(Integer, primary_key=True)
name = Column(String(255, 'utf8mb4_general_ci'), nullable=False)
created_at = Column(DateTime, nullable=False)
updated_at = Column(DateTime, nullable=False)

tablename设置为数据库中对映的表格名称,接着通过flask_sqlalchemy中的SQLAlchemy可以将models.py中定义完成的类,以表的形式在数据库中生成。

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
# 在完成了db.init_app(app)将app与db绑定后,执行create_all()生成数据库表
db.create_all()

如果想要对数据库中的表进行改动(增删字段等操作),也可以通过修改models.py中的模型,然后同步更新到数据库。

需要用到flask-migrate

安装依赖

pip install flask-migrate

在app.py中引入Migrate

migrate = Migrate(app, db)

大致可以分为三步:

#  first step
flask db init
# second step
flask db migrate
# third step
flask db upgrade

在执行完第一步完成初始化之后,后续更新数据库的表只需要执行后两步即可,即flask db migrate和flask db upgrade

在Flask中不需要编写sql语句,可以通过db.session只通过对类进行操作来实现数据库的增删改查

insert

大致步骤为创建一个实体类的对象对应数据库中表的一行数据;使用db.session添加并提交

#  创建Room对象
room = Room(hotel_id=hotel_id, original_price=original_price, price=price, num=num, type=room_type, created_at=now, updated_at=now)
# 将其在会话中插入
db.session.add(room)
# 提交
db.session.commit()

select

查询一条数据,可以使用class.query.get()

根据条件查询数据集合,则需要用到filter进行过滤,可以得到一个集合

.all()可以获取全部的数据; .first()能够获得第一条数据

#  根据主键查询一行数据,并映射到实体类对象
room = Room.query.get(room_id)
# 按照一定的条件查询(使用过滤器)
hotel_facilities = HotelFacility.query.filter_by(hotel_id=hotel.id).all()
# 获取集合中第一个满足该条件的数据行
user = User.query.filter_by(email=email).first()

update

先在数据库中查询到对应的数据映射到一个对象中;修改对象的属性;使用db.session完成commit

room = Room.query.get(room_id)
room.original_price = float(form.original_price.data)
room.price = float(form.price.data)
room.num = int(form.num.data)
room.room_type = form.room_type.data
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
room.updated_at = now
# 数据库更新
db.session.commit()

delete

删除需要先查询到该条记录,然后使用会话进行删除

# 删除设施记录  
facility = Facility.query.get(1)
db.session.delete(facility)
db.session.commit()

blueprints

blueprints(蓝图)能够降低app.py中代码的复杂度,同时可以将功能模块进行拆解,便于维护,类似spring中的controller

只需要在app.py中注册该蓝图,然后在蓝图中编写请求url对应的前缀,路由以及请求方法等即可

from flask import Blueprint, request, g, redirect, render_template, url_for
from models import Hotel
from ext import db
from datetime import datetime
from .form import HotelForm

bp = Blueprint("hotels", __name__, url_prefix="/hotels")


# 添加酒店
@bp.route("/addHotel", methods=["GET", "POST"])
def add_hotel():
if request.method == "GET":
return render_template('add_hotel.html')
else:
form = HotelForm(request.form)
if form.validate():
name = form.name.data
address = form.address.data
introduction = form.introduction.data
phone = form.phone.data
stars = form.stars.data
brand = form.brand.data
business_district = form.business_district.data
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
hotel = Hotel(name=name, address=address, introduction=introduction, phone=phone, stars=stars, brand=brand, business_district=business_district, created_at=now, updated_at=now)
db.session.add(hotel)
db.session.commit()
return redirect(url_for('auth.index'))
else:
print(form.errors)
return "添加酒店失败,检查填写信息是否正确"

2024.3.13更新

多线程

Flask通过app.run(threaded=True)开启的多线程处理,并不是指同一路由开启多个线程处理,而是不同路由使用多个线程处理

if __name__ == '__main__':
app.run(threaded=True)

简单来说,threaded为True ,同时访问 /t1 和 /t2 路由 ,5秒后/t1 和 /t2 一起返回结果
threaded为False ,同时访问 /t1 和 /t2 路由 ,5秒后/t1返回结果,10秒后/t2返回结果

@app.route('/t1')
def t1():
sleep(5)
return 'Hello World t1'

@app.route('/t2')
def t2():
sleep(5)
return 'Hello World t2'

最后

希望有机会还能用到Flask😂😂😂