小工具知识网

当前位置: 首页 > 行业知识 > [记录]基于Flask Web全栈开发实战-项目实战·上篇(黄勇 • 著)

行业知识

[记录]基于Flask Web全栈开发实战-项目实战·上篇(黄勇 • 著)

2026-11-03 15:33:26 来源:互联网转载

说明

基于书籍《Flask Web全栈开发实战》【黄勇·著】第9章项目实战

创建项目

代码环境:pycharm

File->New Project->Flask

安装相应的python 包

# 用于flask在使用ORM模型操作数据库pip install flask-sqlalchemy # Python操作数据库的驱动程序pip install pymysql# 对密码加密和解密pip install cryptography# 用于将ORM模型的变更同步到数据库中pip install flask-migrate

config.py文件

在根目录下,常见一个config.py的python文件,用来存放配置项。

class BaseConfig:    SECRET_KEY = 'linql_test'    SQLALCHEMY_TRACK_MODIFICATIONS = False# 开发环境class DevelopmentConfig(BaseConfig):    # 配置连接数据库    HOSTNAME = '192.168.3.5' #服务器地址    PORT = 3306 #默认端口号    USERNAME = 'root'    PASSWORD = 'root'    DATABASE = 'pythonbbs' #数据库名    SQLALCHEMY_DATABASE_URI =  f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"   #  测试环境class TestingConfig(BaseConfig):    # 配置连接数据库    HOSTNAME = '192.168.3.5'  # 服务器地址    PORT = 3306  # 默认端口号    USERNAME = 'root'    PASSWORD = 'root'    DATABASE = 'pythonbbs'  # 数据库名    SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"# 生产部署环境class ProductionConfig(BaseConfig):    # 配置连接数据库    HOSTNAME = '192.168.3.5'  # 服务器地址    PORT = 3306  # 默认端口号    USERNAME = 'root'    PASSWORD = 'root'    DATABASE = 'pythonbbs'  # 数据库名    SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"

在app.py中,绑定配置

from flask import Flaskimport configapp = Flask(__name__)# 引入开发环境app.config.from_object(config.DevelopmentConfig)@app.route('/')def hello_world():    return 'Hello World!'if __name__ == '__main__':    app.run()

exts.py文件

在根目录里创建exts.py文件,主要用来存放一些第三方插件的对象。

如:SQLAlchemy对象、Flask-Mail对象等。

目的,是为了防止循环引用。

from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()

回到app.py中,然后导入db变量,再通过db.init_app(app)完成初始化。

from flask import Flaskimport configfrom exts import dbapp = Flask(__name__)# 引入开发环境app.config.from_object(config.DevelopmentConfig)# 初始化dbdb.init_app(app)@app.route('/')def hello_world():    return 'Hello World!'if __name__ == '__main__':    app.run()

blueprints模块

通过蓝图来模块化,创建一个blueprints的包,用于存放蓝图模块。

在项目名称上右击,New->Python Package

并在,blueprints下,分别创建名为:cms、front和user的python文件

在cms.py中创建蓝图对象

from flask import Blueprintbp = Blueprint("cms",__name__,url_prefix="/cms")

在front.py中创建蓝图对象

from flask import Blueprintbp = Blueprint("front",__name__,url_prefix="")

在user.py中创建蓝图对象

from flask import Blueprintbp = Blueprint("user",__name__,url_prefix="/user")

创建了蓝图对象,并指定了url前缀,因front是面向前台的,所以url为空

创建蓝图对象后,还需要在app.py中完成注册。

from flask import Flaskimport configfrom exts import dbfrom blueprints.cms import bp as cms_bpfrom blueprints.front import bp as front_bpfrom blueprints.user import bp as user_bpapp = Flask(__name__)# 引入开发环境app.config.from_object(config.DevelopmentConfig)# 初始化dbdb.init_app(app)# 注册蓝图app.register_blueprint(cms_bp)app.register_blueprint(front_bp)app.register_blueprint(user_bp)@app.route('/')def hello_world():    return 'Hello World!'if __name__ == '__main__':    app.run()

models模块

在根目录下,创建一个名为models的Python Package,然后在models下分别创建user.py和post.py,用来存放与用户和帖子相关的ORM模型。

创建用户相关模型

创建权限和角色模型

用户系统最核心的部分就是用户相关的ORM模型。

该系统的前台和后台用的是同一个用户系统,而后台系统中需要角色和权限管理。

首先,来添加权限ORM模型,在models/user.py中添加以下代码:

from exts import dbfrom datetime import datetimefrom enum import Enum# PermissionEnum 枚举类型# 存放权限类型的枚举class PermissionEnum(Enum):    BOARD = "板块"    POST = "帖子"    COMMENT = "评论"    FRONT_USER = "前台用户"    CMS_USER = "后台用户"# PermissionModel模型# name 从PermissionEnum 枚举取class PermissionModel(db.Model):    __tablename__="permission"    id = db.Column(db.Integer,primary_key=True,autoincrement=True)    name = db.Column(db.Enum(PermissionEnum),nullable=False,unique=True)# 中间表# role_id来引用role表# permission_id来引用permission表role_permission_table=db.Table(    "role_permission_table",    db.Column("role_id",db.Integer,db.ForeignKey("role.id")),    db.Column("permission_id",db.Integer,db.ForeignKey("permission.id")))class RoleModel(db.Model):    __tablename__="role"    # 主键id    id = db.Column(db.Integer,primary_key=True,autoincrement=True)    # 角色名称    name = db.Column(db.String(100),nullable=False)    # 角色描述    desc = db.Column(db.String(100),nullable=False)    # 创建时间    create_time = db.Column(db.Datetime,default=datetime.now)    # 关系属性(RoleModel和PermissionModel属于多对多关系)    # role_permission_table 中间表    permissions = db.relationship("PermissionModel",secondary=role_permission_table,backref="roles")

在PermissionModel和RoleModel创建完成后,将模型映射到数据库中,需要借助Flask-Migrate插件

在app.py中,创建Migrate对象

from flask import Flaskimport configfrom exts import dbfrom blueprints.cms import bp as cms_bpfrom blueprints.front import bp as front_bpfrom blueprints.user import bp as user_bpfrom flask_migrate import Migrateapp = Flask(__name__)# 引入开发环境app.config.from_object(config.DevelopmentConfig)# 初始化dbdb.init_app(app)# 注册蓝图app.register_blueprint(cms_bp)app.register_blueprint(front_bp)app.register_blueprint(user_bp)# 创建Migrate对象migrate = Migrate(app,db)@app.route('/')def hello_world():    return 'Hello World!'if __name__ == '__main__':    app.run()

为了迁移时能让程序识别到models/user.py中的ORM模型,需要导入

from models import user
---------------------------------------------------------------------------ModuleNotFoundError                       Traceback (most recent call last)Cell In[5], line 1----> 1 from models import userModuleNotFoundError: No module named 'models'

在pyCharm的Terminal中执行以下命令,以生成迁移脚本,并完成迁移脚本的执行。

(pythonWeb) linql@localhost flaskDemo1 % flask db migrate -m "create permission and role model"Error: Path doesn't exist: '/Users/linql/Desktop/code_Deeplearn/flaskDemo1/migrations'.  Please use the 'init' command to create a new scripts folder.

上面运行,会报错。提示需要先“init”

# 先执行flask db init# 再执行flask db migrate -m "create permission and role model"

执行以上命令后,已经为ORM模型生成了迁移脚本。

但,此时并没有真正同步到数据库中,还需要执行以下命令才会实现同步到数据库中。

flask db upgrade

创建权限和角色

Flask 项目 如何创建命令

在flask安装时,默认会安装click库

click库,主要作用是用来实现命令,Flask已经针对click库进行了集成,通过app.cli即可访问到click对象。

下面是一个简单的命令测试

from flask import Flaskimport configfrom exts import dbfrom blueprints.cms import bp as cms_bpfrom blueprints.front import bp as front_bpfrom blueprints.user import bp as user_bpfrom flask_migrate import Migratefrom models import userimport clickapp = Flask(__name__)# 引入开发环境app.config.from_object(config.DevelopmentConfig)# 初始化dbdb.init_app(app)# 注册蓝图app.register_blueprint(cms_bp)app.register_blueprint(front_bp)app.register_blueprint(user_bp)# 创建Migrate对象migrate = Migrate(app,db)@app.route('/')def hello_world():    return 'Hello World!'@app.cli.command("my-command")def my_command():    click.echo("这是我的自定义命令!")if __name__ == '__main__':    app.run()

通过装饰器@app.cli.command,将my_command函数添加到命令中,并且指定命令的名称为my-command。

然后,再在pycharm的terminal中输入以下命令。

flask my-command

在app.py中,实现一个名叫create-permission的命令。

针对每个模块分别添加一个权限。

from flask import Flask  import configfrom exts import dbfrom blueprints.cms import bp as cms_bpfrom blueprints.front import bp as front_bpfrom blueprints.user import bp as user_bpfrom flask_migrate import Migratefrom models.user import PermissionEnum,PermissionModel,RoleModelimport clickapp = Flask(__name__)# 引入开发环境app.config.from_object(config.DevelopmentConfig)# 初始化dbdb.init_app(app)# 注册蓝图app.register_blueprint(cms_bp)app.register_blueprint(front_bp)app.register_blueprint(user_bp)# 创建Migrate对象migrate = Migrate(app,db)@app.route('/')def hello_world():    return 'Hello World!'# 测试命令@app.cli.command("my-command")def my_command():    click.echo("这是我的自定义命令!")# 创建create-permission命令@app.cli.command("create-permission")def create_permission():    for permission_name in dir(PermissionEnum):        if permission_name.startswith("__"):            continue        permission = PermissionModel(name=getattr(PermissionEnum,permission_name))        db.session.add(permission)    db.session.commit()    click.echo("权限添加成功")if __name__ == '__main__':    app.run()

然后,再在pycharm的terminal中输入以下命令。

flask create-permission

权限创建成功后,再添加角色。

创建3个角色,分别为:稽查、运营、管理员。

角色名,稽查,权限:帖子、评论

角色名,运营,权限:板块、帖子、评论、前台用户

角色名,管理员,权限:板块、帖子、评论、前台用户、后台用户

创建角色,同创建权限一样操作,下面只给出代码,执行步骤一致

from flask import Flaskimport configfrom exts import dbfrom blueprints.cms import bp as cms_bpfrom blueprints.front import bp as front_bpfrom blueprints.user import bp as user_bpfrom flask_migrate import Migratefrom models.user import PermissionEnum, PermissionModel, RoleModelimport clickapp = Flask(__name__)# 引入开发环境app.config.from_object(config.DevelopmentConfig)# 初始化dbdb.init_app(app)# 注册蓝图app.register_blueprint(cms_bp)app.register_blueprint(front_bp)app.register_blueprint(user_bp)# 创建Migrate对象migrate = Migrate(app, db)@app.route('/')def hello_world():    return 'Hello World!'# 测试命令@app.cli.command("my-command")def my_command():    click.echo("这是我的自定义命令!")# 创建添加权限的命令create-permission@app.cli.command("create-permission")def create_permission():    for permission_name in dir(PermissionEnum):        if permission_name.startswith("__"):            continue        permission = PermissionModel(name=getattr(PermissionEnum, permission_name))        db.session.add(permission)    db.session.commit()    click.echo("权限添加成功")# 创建添加角色的命令create-role@app.cli.command("create-role")def create_role():    # 稽查    inspector = RoleModel(name="稽查", desc="负责审核帖子和评论是否合法合规")    inspector.permissions = PermissionModel.query.filter(        PermissionModel.name.in_([PermissionEnum.POST, PermissionEnum.COMMENT])).all()    # 运营    operator = RoleModel(name="运营", desc="负责网站持续正常运营!")    operator.permissions = PermissionModel.query.filter(PermissionModel.name.in_(        [PermissionEnum.POST, PermissionEnum.COMMENT, PermissionEnum.BOARD, PermissionEnum.FRONT_USER,         PermissionEnum.CMS_USER])).all()    # 管理员    administrator = RoleModel(name="管理员", desc="负责整个网站所有工作!")    administrator.permissions = PermissionModel.query.all()    db.session.add_all([inspector,operator,administrator])    db.session.commit()    click.echo("角色创建成功!")if __name__ == '__main__':    app.run()
# 在pycharm中的terminal中运行flask create-role

对app.py进行瘦身,将command部分的代码放到commands.py里

# commands.pyfrom models.user import PermissionEnum, PermissionModel, RoleModelimport clickfrom exts import db# 测试命令# @app.cli.command("my-command")def my_command():    click.echo("这是我的自定义命令!")# 创建添加权限的命令create-permission# @app.cli.command("create-permission")def create_permission():    for permission_name in dir(PermissionEnum):        if permission_name.startswith("__"):            continue        permission = PermissionModel(name=getattr(PermissionEnum, permission_name))        db.session.add(permission)    db.session.commit()    click.echo("权限添加成功")# 创建添加角色的命令create-role# @app.cli.command("create-role")def create_role():    # 稽查    inspector = RoleModel(name="稽查", desc="负责审核帖子和评论是否合法合规")    inspector.permissions = PermissionModel.query.filter(        PermissionModel.name.in_([PermissionEnum.POST, PermissionEnum.COMMENT])).all()    # 运营    operator = RoleModel(name="运营", desc="负责网站持续正常运营!")    operator.permissions = PermissionModel.query.filter(PermissionModel.name.in_(        [PermissionEnum.POST, PermissionEnum.COMMENT, PermissionEnum.BOARD, PermissionEnum.FRONT_USER,         PermissionEnum.CMS_USER])).all()    # 管理员    administrator = RoleModel(name="管理员", desc="负责整个网站所有工作!")    administrator.permissions = PermissionModel.query.all()    db.session.add_all([inspector,operator,administrator])    db.session.commit()    click.echo("角色创建成功!")
# app.py文件from flask import Flaskimport configfrom exts import dbfrom blueprints.cms import bp as cms_bpfrom blueprints.front import bp as front_bpfrom blueprints.user import bp as user_bpfrom flask_migrate import Migrate# 引入了命令import commandsapp = Flask(__name__)# 引入开发环境app.config.from_object(config.DevelopmentConfig)# 初始化dbdb.init_app(app)# 注册蓝图app.register_blueprint(cms_bp)app.register_blueprint(front_bp)app.register_blueprint(user_bp)# 创建Migrate对象migrate = Migrate(app, db)# 添加命令app.cli.command("create-permission")(commands.create_permission)app.cli.command("create-role")(commands.create_role)app.cli.command("my-command")(commands.my_command) #瘦身后,再次测试@app.route('/')def hello_world():    return 'Hello World!'if __name__ == '__main__':    app.run()

创建用户模型

UUID(universally unique identfier)

UUID的长度为32字符,再加上4个横线,总共有36个字符。

引入python第三方库,shortuuid

shortuuid 会对原始UUID进行base57 编码,然后删除相似的字符,如:I,1,L,o和0,最后生成默认22位长度的字符串。

# 安装shortuuid库pip install shortuuid

重构UserModel

from exts import dbfrom datetime import datetimefrom enum import Enum# 引入shortuuidfrom shortuuid import uuid# 引入加密和验证from werkzeug.security import generate_password_hash,check_password_hash# PermissionEnum 枚举类型# 存放权限类型的枚举class PermissionEnum(Enum):    BOARD = "板块"    POST = "帖子"    COMMENT = "评论"    FRONT_USER = "前台用户"    CMS_USER = "后台用户"# PermissionModel模型# name 从PermissionEnum 枚举取class PermissionModel(db.Model):    __tablename__ = "permission"    id = db.Column(db.Integer, primary_key=True, autoincrement=True)    name = db.Column(db.Enum(PermissionEnum), nullable=False, unique=True)# 中间表# role_id来引用role表# permission_id来引用permission表role_permission_table = db.Table(    "role_permission_table",    db.Column("role_id", db.Integer, db.ForeignKey("role.id")),    db.Column("permission_id", db.Integer, db.ForeignKey("permission.id")))class RoleModel(db.Model):    __tablename__ = "role"    # 主键id    id = db.Column(db.Integer, primary_key=True, autoincrement=True)    # 角色名称    name = db.Column(db.String(100), nullable=False)    # 角色描述    desc = db.Column(db.String(100), nullable=False)    # 创建时间    create_time = db.Column(db.DateTime, default=datetime.now)    # 关系属性(RoleModel和PermissionModel属于多对多关系)    # role_permission_table 中间表    permissions = db.relationship("PermissionModel", secondary=role_permission_table, backref="roles")class UserModel(db.Model):    __tablename__ = "user"    # 主键    id = db.Column(db.String(100), primary_key=True, default=uuid)    # 用户名,不能为空,且值唯一    username = db.Column(db.String(50), nullable=False, unique=True)    # 密码,最大长度200,应该先加密再存储    _password = db.Column(db.String(200), nullable=False)    # 邮箱,不能为空,且值唯一    email = db.Column(db.String(50), nullable=False, unique=True)    # 头像,存储图片在服务器中保存的路径,可以为空    avatar = db.Column(db.String(100))    # 签名,可以为空    signature = db.Column(db.String(100))    # 加入时间,第一次存储,默认当前时间    join_time = db.Column(db.DateTime, default=datetime.now)    # 是否员工,只有员工才能进入后台系统,默认为False    is_staff = db.Column(db.Boolean, default=False)    # 是否可用,默认情况下是可用    is_active = db.Column(db.Boolean, default=True)    is_admin = db.Column(db.Boolean,default=False)    # 外键    # 角色外键,引用role表的id字段    role_id = db.Column(db.Integer,db.ForeignKey("role.id"))    # 关系属性,引用RoleModel    role = db.relationship("RoleModel",backref="users")    def __init__(self,*args,**kwargs):        if "password" in kwargs:            self.password = kwargs.get("password")            kwargs.pop("password")        super(UserModel,self).__init__(*args,**kwargs)    @property    def password(self):        return self._password    @password.setter    def password(self,raw_password):        self._password=generate_password_hash(raw_password)    def check_password(self,raw_password):        result = check_password_hash(self.password,raw_password)        return result    def has_permission(self,permission):        return permission in [permission.name for permisson in self.role.permissions]
# 在terminal中运行flask db migrate -m "create user model"flask db upgrade

创建测试用户

为了方便后续开发,按照角色个数创建3个员工账户。

在commands.py文件中,添加以下代码

#     添加测试3个角色的测试用户def create_test_user():    admin_role = RoleModel.query.filter_by(name="管理员").first()    zhangsan = UserModel(username ="张三",email="zhangsan@zlkt.net",password="111111",is_staff=True,role=admin_role)    operator_role = RoleModel.query.filter_by(name="运营").first()    lisi = UserModel(username ="李四",email="lisi@zlkt.net",password="111111",is_staff=True,role=operator_role)    inspector_role = RoleModel.query.filter_by(name="稽查").first()    wangwu = UserModel(username="王五", email="wangwu@zlkt.net", password="111111", is_staff=True, role=inspector_role)    db.session.add_all([zhangsan,lisi,wangwu])    db.session.commit()    click.echo("测试用户添加成功!")

在app.py中添加,以下代码:

# 添加命令(增加3个角色测试用户)app.cli.command("create-test-user")(commands.create_test_user)

在pycharm的terminal中,运行命令

flask create-test-user

创建管理员

在commands.py中添加以下命令:

# 创建管理员@click.option("--username",'-u')@click.option("--email",'-e')@click.option("--password",'-p')def create_admin(username,email,password):         admin_role = RoleModel.query.filter_by(name="管理员").first()    admin_user = UserModel(username=username,email=email,password=password,is_staff=True,role = admin_role)    db.session.add(admin_user)    db.session.commit()    click.echo("管理员创建成功")

其中,通过@click.option装饰器添加了3个参数。

以后在命令行中即可使用–username,–email,–password将用户名、邮箱、密码当作参数传递到函数中。

注册

渲染注册模版

因,未直接下载书籍自带的源码,只能手动自行编辑。

1、在根目录的static文件下,创建一个文件夹,名为:front

2、在front文件夹下,创建一个文件夹,名为:css

3、在css文件夹下,创建2个文件,分别为:base.css、sign.css

1、再在根目录的templates文件夹下,创建一个文件夹,名为:front

2、在front文件夹下,创建2个文件,分别为:base.html、register.html

# base.html                    

上一篇:【Javascript】设计模式之发布订阅模式

下一篇:路由器怎么换服务器?