本文记录了一些关于Flask的基本概念与使用方法。Flask是一个轻量级的web框架,支持前后端整合,并且可在前端中直接使用相关的python语句。支持ORM(Object Relational Mapping),很好的结合mvc模式进行开发。
依赖安装 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" 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, gfrom ext import db, mailfrom blueprints.auth import bp as auth_bpfrom blueprints.users import bp as user_bpfrom blueprints.hotels import bp as hotel_bpfrom blueprints.rooms import bp as room_bpfrom models import Userimport configapp = 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 SQLAlchemydb = SQLAlchemy() db.create_all()
如果想要对数据库中的表进行改动(增删字段等操作),也可以通过修改models.py中的模型,然后同步更新到数据库。
需要用到flask-migrate
安装依赖
pip install flask-migrate
在app.py中引入Migrate
migrate = Migrate(app, db)
大致可以分为三步:
flask db init flask db migrate flask db upgrade
在执行完第一步完成初始化之后,后续更新数据库的表只需要执行后两步即可,即flask db migrate和flask db upgrade
在Flask中不需要编写sql语句,可以通过db.session只通过对类进行操作来实现数据库的增删改查
insert 大致步骤为创建一个实体类的对象对应数据库中表的一行数据;使用db.session添加并提交
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_forfrom models import Hotelfrom ext import dbfrom datetime import datetimefrom .form import HotelFormbp = 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😂😂😂