更新文档

This commit is contained in:
wojiaoyishang
2025-01-27 19:48:27 +08:00
parent 155af93c77
commit 5153daf7da
39 changed files with 767 additions and 593 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

+20 -8
View File
@@ -1,7 +1,7 @@
:mod:`admin` -- 后台函数模块
=======================================
:mod:`admin` 模块源代码在文件 `applications/common/admin.py` 下,主要集结了一些常用的后台需要频繁调用的函数。
:mod:`admin` 模块源代码在文件 `applications/common/admin.py` 下,主要集结了一些常用的后台需要频繁调用的函数。
.. module:: admin
@@ -10,9 +10,21 @@
.. function:: get_captcha()
生成验证码图片及其对应的验证码字符串。
生成验证码图片及其对应的验证码字符串。
:return: 返回验证码图片的响应对象和验证码字符串。
:return: 返回验证码图片的响应对象和验证码字符串。
**示例:**
.. code-block:: python
from applications.common.admin import get_captcha
@bp.get('/getCaptcha')
def captcha():
resp, code = get_captcha()
session["code"] = code
return resp
.. function:: normal_log(method, url, ip, user_agent, desc, uid, is_access)
@@ -31,12 +43,12 @@
.. function:: login_log(request, uid, is_access)
记录用户登录日志。
记录用户登录日志。
:param request: Flask 请求对象。
:param uid: 用户 ID。
:param is_access: 是否成功登录(True 或 False)。
:return: 返回日志记录的 ID。
:param request: Flask 请求对象。
:param uid: 用户 ID。
:param is_access: 是否成功登录(True 或 False)。
:return: 返回日志记录的 ID。
.. function:: admin_log(request, is_access, desc=None)
+90
View File
@@ -0,0 +1,90 @@
:mod:`curd` -- 简单增删改查模块
=======================================
:mod:`curd` 模块源代码在文件 `applications/common/curd.py` 下,主要集结了一些简单实用的增删改查。
.. module:: curd
-------
.. class:: LogicalDeleteMixin
逻辑删除混入类,为模型提供软删除功能。
**示例:**
.. code-block:: python
class Test(db.Model, LogicalDeleteMixin):
__tablename__ = 'admin_test'
id = db.Column(db.Integer, primary_key=True, comment='角色ID')
# 软删除
Test.query.filter_by(id=1).soft_delete()
# 查询所有未删除的记录
Test.query.logic_all()
函数
--------------
.. function:: auto_model_jsonify(data, model: db.Model)
自动序列化模型数据为 JSON 格式,无需手动定义 Schema。
**示例:**
.. code-block:: python
power_data = curd.auto_model_jsonify(model=Dept, data=dept)
:param data: 需要序列化的 SQLAlchemy 查询结果。
:param model: SQLAlchemy 模型类。
:return: 返回序列化后的 JSON 数据。
.. function:: model_to_dicts(schema: ma.Schema, data)
使用指定的 Schema 序列化 SQLAlchemy 查询结果。
:param schema: Marshmallow Schema 类。
:param data: SQLAlchemy 查询结果。
:return: 返回序列化后的数据,返回字典。
.. function:: get_one_by_id(model: db.Model, id)
根据 ID 查询单个记录。
:param model: SQLAlchemy 模型类。
:param id: 记录的主键 ID。
:return: 返回查询到的记录,如果未找到则返回 None。
.. function:: delete_one_by_id(model: db.Model, id)
根据 ID 删除单个记录。
:param model: SQLAlchemy 模型类。
:param id: 记录的主键 ID。
:return: 返回删除操作影响的行数。
.. function:: enable_status(model: db.Model, id)
启用指定 ID 的记录。
:param model: SQLAlchemy 模型类。
:param id: 记录的主键 ID。
:return: 如果操作成功返回 True,否则返回 False。
.. function:: disable_status(model: db.Model, id)
停用指定 ID 的记录。
:param model: SQLAlchemy 模型类。
:param id: 记录的主键 ID。
:return: 如果操作成功返回 True,否则返回 False。
+121
View File
@@ -0,0 +1,121 @@
.. _字段构造模块:
:mod:`helper` -- 字段构造模块
=======================================
:mod:`helper` 模块源代码在文件 `applications/common/helper.py` 下,主要集结了一些常用的字段构造方法。
.. module:: helper
--------
.. class:: ModelFilter
ORM 多条件查询构造器,支持多种查询条件组合。
**示例:**
.. code-block:: python
from applications.common.helper import ModelFilter
mf = ModelFilter()
mf.exact('name', 'John') # 添加精确匹配条件
mf.vague('email', 'example.com') # 添加模糊匹配条件
query = User.query.filter(mf.get_filter(User))
.. attribute:: filter_field
存储字段过滤条件的字典。
.. attribute:: filter_list
存储最终的过滤条件列表。
.. method:: __init__()
初始化过滤条件存储字典和列表。
.. method:: exact(field_name, value)
添加精确匹配条件。
:param field_name: 模型字段名称。
:param value: 匹配的值。
.. method:: neq(field_name, value)
添加不等于条件。
:param field_name: 模型字段名称。
:param value: 不匹配的值。
.. method:: greater(field_name, value)
添加大于条件。
:param field_name: 模型字段名称。
:param value: 大于的值。
.. method:: less(field_name, value)
添加小于条件。
:param field_name: 模型字段名称。
:param value: 小于的值。
.. method:: vague(field_name, value: str)
添加模糊匹配条件(左右模糊)。
:param field_name: 模型字段名称。
:param value: 模糊匹配的值。
.. method:: left_vague(field_name, value: str)
添加左模糊匹配条件。
:param field_name: 模型字段名称。
:param value: 左模糊匹配的值。
.. method:: right_vague(field_name, value: str)
添加右模糊匹配条件。
:param field_name: 模型字段名称。
:param value: 右模糊匹配的值。
.. method:: contains(field_name, value: str)
添加包含条件。
:param field_name: 模型字段名称。
:param value: 包含的值。
.. method:: between(field_name, value1, value2)
添加范围查询条件。
:param field_name: 模型字段名称。
:param value1: 范围起始值。
:param value2: 范围结束值。
.. method:: get_filter(model: db.Model)
获取最终的 SQLAlchemy 过滤条件。
:param model: SQLAlchemy 模型类。
:return: 返回组合后的过滤条件。
+2
View File
@@ -9,6 +9,8 @@
:maxdepth: 1
admin
curd
helper
辅助函数
------------
+1 -1
View File
@@ -1,7 +1,7 @@
:mod:`cache` -- 应用缓存模块
================================
:mod:`cache` 模块源代码在文件 `applications/common/utils/cache.py` 下,主要用于简单的程序数据缓存。
:mod:`cache` 模块源代码在文件 `applications/common/utils/cache.py` 下,主要用于简单的程序数据缓存。
目前此模块仅启用应用程序缓存,暂时没有联动 Redis 等数据库缓存的功能,后续有意向添加。您可以在自己的项目中添加相关的函数,当然也非常欢迎提交 PR ,一起完善项目。
+1 -1
View File
@@ -1,7 +1,7 @@
:mod:`captcha` -- 验证码生成模块
==================================
:mod:`captcha` 模块源代码在文件 `applications/common/utils/captcha.py` 下,主要用于生成验证码图片。
:mod:`captcha` 模块源代码在文件 `applications/common/utils/captcha.py` 下,主要用于生成验证码图片。
.. module:: captcha
+21 -1
View File
@@ -1,7 +1,9 @@
.. _JSON 响应正文生成模块:
:mod:`http` -- JSON 响应正文生成模块
=======================================
:mod:`http` 模块源代码在文件 `applications/common/utils/http.py` 下,主要用于生成 JSON 格式的响应正文。
:mod:`http` 模块源代码在文件 `applications/common/utils/http.py` 下,主要用于生成 JSON 格式的响应正文。
对于大部分 JSON 格式响应的数据,请尽量遵循响应格式规范。如此方便后续前后端的分离和项目的构建。
@@ -36,4 +38,22 @@
:param limit: 每页数据条数,默认为 10。
:return: 返回 JSON 格式的响应,包含 `msg`、`code`、`data`、`count` 和 `limit` 字段。
**示例:**
.. code-block:: python
from applications.common.utils.http import success_api, fail_api
@bp.get('/init')
def init():
if ...:
return success_api(msg="初始化成功")
return fail_api(msg="初始化失败")
.. code-block:: python
from applications.common.utils.http import table_api
@bp.get('/data')
def data():
return table_api(data=[], total=0)
+1 -1
View File
@@ -3,7 +3,7 @@
目录索引
.. toctree::
:maxdepth: 1
:maxdepth: 2
cache
captcha
+20 -7
View File
@@ -1,7 +1,11 @@
.. _邮件模块:
:mod:`mail` -- 邮件模块
==================================
:mod:`mail` 模块源代码在文件 `applications/common/utils/mail.py` 下,主要用于邮件的发送。
:mod:`mail` 模块源代码在文件 `applications/common/utils/mail.py` 下,主要用于邮件的发送。
使用前,需要正确在 `applications/config.py` 中配置 SMTP 服务器。
.. module:: mail
@@ -31,14 +35,23 @@
.. function:: add(receiver, subject, content, user_id)
发送一封邮件,并将发送记录保存到数据库。 **该方法被邮件发送的视图函数调用。**
发送一封邮件,并将发送记录保存到数据库。 **该方法被邮件发送的视图函数调用。**
:param receiver: 接收者邮箱地址,多个邮箱用英文分号隔开。
:param subject: 邮件主题。
:param content: 邮件内容(HTML 格式)。
:param user_id: 发送者用户ID,表示谁发送了这封邮件。
:param receiver: 接收者邮箱地址,多个邮箱用英文分号隔开。
:param subject: 邮件主题。
:param content: 邮件内容(HTML 格式)。
:param user_id: 发送者用户ID,表示谁发送了这封邮件。
可以使用 `from flask_login import current_user; current_user.id` 获取当前登录用户的ID。
:return: 发送成功返回 True,失败报错。
:return: 发送成功返回 True,失败报错。
**示例**
.. code-block:: python
from flask_login import current_user
from applications.common.utils import mail
mail.add("test@test.com", "subject", "<h1>Hello</h1>", current_user.id)
.. function:: delete(id)
+5 -1
View File
@@ -1,7 +1,9 @@
.. _权限验证模块:
:mod:`rights` -- 权限验证模块
==================================
:mod:`rights` 模块源代码在文件 `applications/common/utils/rights.py` 下,主要用于权限验证。
:mod:`rights` 模块源代码在文件 `applications/common/utils/rights.py` 下,主要用于权限验证。
.. module:: rights
@@ -23,6 +25,8 @@
.. code-block:: python
from applications.common.utils.rights import authorize
@app.route("/test")
@authorize("system:power:remove", log=True)
def test_index():
+1 -1
View File
@@ -1,7 +1,7 @@
:mod:`upload` -- 文件上传模块
==================================
:mod:`upload` 模块源代码在文件 `applications/common/utils/upload.py` 下,主要用于文件上传,目前主要用于图片上传。
:mod:`upload` 模块源代码在文件 `applications/common/utils/upload.py` 下,主要用于文件上传,目前主要用于图片上传。
.. module:: upload
+1 -1
View File
@@ -1,7 +1,7 @@
:mod:`validate` -- 效验模块
==================================
:mod:`validate` 模块源代码在文件 `applications/common/utils/validate.py` 下,主要用于数据效验与过滤。
:mod:`validate` 模块源代码在文件 `applications/common/utils/validate.py` 下,主要用于数据效验与过滤。
.. module:: validate
+6
View File
@@ -21,3 +21,9 @@
function/index
.. toctree::
:maxdepth: 1
:caption: 最佳实践
practices/index
+9
View File
@@ -0,0 +1,9 @@
.. title:: 最佳实践
目录索引
.. toctree::
:maxdepth: 1
plugin
trick
+129
View File
@@ -0,0 +1,129 @@
插件开发
=================
插件功能旨在最大限度不修改原框架的前提下添加新功能,并可以像程序原有框架一样进行流程注册,而且不需要修改任何程序框架原有代码(仅在配置文件中设置即可)。
所有插件放置在 `plugins` 文件夹中,项目提供了三个示例插件,分别是 `helloworld``realip``replacePage` ,分别用于示例页面的注册、修改 Flask 上下文和页面替换。
像项目自带的用户管理、部门管理等基本功能属于程序自身的“功能插件”,对于大多数衍生项目来说,多的是修改字符串和删除部分不需要的功能,
而插件开发主要可以用于添加自己的视图函数和功能,可以完美于项目融合,增加可拓展性。
插件的启用
-----------------
插件需要在 `applications/config.py` 中配置,你会找到如下的内容:
.. code-block:: python
PLUGIN_ENABLE_FOLDERS = []
而在目录 `plugins` 中,你会发现存在 文件夹名称 为 `helloworld``realip``replacePage` 三个插件。比如我们想要启用 `helloworld` 插件,
仅需要做如下修改:
.. code-block:: python
PLUGIN_ENABLE_FOLDERS = ["helloworld"]
假设有多个插件,只要依次在列表 `PLUGIN_ENABLE_FOLDERS` 中填入插件的文件夹名称即可。**注意:填写的先后顺序会影响插件加载的前后顺序,越前面的插件越早被加载。**
假设插件启用成功,你将会在控制台收到如下的提示:
.. code-block:: bash
* Plugin: Loaded plugin: Hello World .
|
.. image:: ../_static/plugin_run.png
:align: center
|
`helloworld` 插件启用之后,你可以访问 `http://127.0.0.1:5000/hello_world/` 来请求到新添加的页面。你会发现添加页面变的简单,仅需要修改一下设置项就行了。
|
.. image:: ../_static/helloworld.png
:align: center
|
插件的目录架构
-------------------
插件的目录架构如下:
.. code-block:: bash
Plugin
│ __init__.json
└─ __init__.py
这是一个插件基本的目录架构,插件信息保存在 `__init__.json` 中,其本质是一个包含如下 JSON 字符串的文本文件:
.. code-block:: json
{
"plugin_name": "Hello World",
"plugin_version": "1.0.0.1",
"plugin_description": "一个测试的插件。"
}
这个 JSON 文件中,记录了基本的插件名称与插件版本,以及插件的介绍,请确保一个插件至少包含上述的三个字段,因为这三个字段会被项目所读取并在加载成功之后展示在控制台。
编写插件入口
-------------------
插件入口位于 `__init__.py` 中,请确保 `__init__.py` 文件一定包含 `event_init(app: Flask)` 函数,如下:
.. code-block:: python
def event_init(app: Flask):
pass
这个函数将会在插件加载时被调用,并传入项目的 `Flask` 对象,此后你可以像一般使用 Flask 一样添加视图函数。例如:
.. code-block:: python
def event_init(app: Flask):
@app.get('/test')
def test():
return "这是测试页面"
**当然,不推荐这样直接使用 Flask 对象创建视图函数,更妥当的做法是通过注册蓝图的方式来添加视图函数。您可以这样做:**
在您编写的插件目录下建立一个 `main.py` 文件,并在该文件中添加蓝图:
.. code-block:: python
from flask import render_template, Blueprint
# 创建蓝图
helloworld_blueprint = Blueprint('hello_world', __name__,
template_folder='templates',
static_folder="static",
url_prefix="/hello_world")
@helloworld_blueprint.route("/")
def index():
return render_template("helloworld_index.html")
而后在 `__init__.py` 中注册该蓝图:
.. code-block:: python
from flask import Flask
from .main import helloworld_blueprint
def event_init(app: Flask):
"""初始化完成时会调用这里"""
app.register_blueprint(helloworld_blueprint)
这样可以使目录架构更加清晰。
.. important::
注意不要直接在 `__init__.py``event_init` 函数外直接写存在阻塞的代码,不然项目 Flask 将不能初始化完成。
+199
View File
@@ -0,0 +1,199 @@
开发技巧
===================
开发 Web 过程中需要用到许多技巧来加速开发,本章节将介绍开发的小技巧与一些需要注意的细节。
配置数据库
-----------
项目采用 flask-sqlalchemy,支持多数据库连接,默认是使用 sqlite 的,可以在 `applications/config.py` 中配置,如果需要连接其他数据库需要可以参考:
* HOSTNAME: 指数据库的IP地址
* USERNAME:指数据库登录的用户名
* PASSWORD:指数据库登录密码
* PORT:指数据库开放的端口
* DATABASE:指需要连接的数据库名称
.. code-block:: python
# MSSQL
SQLALCHEMY_DATABASE_URI = f"mssql+pymssql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=cp936"
# mysql
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
# Oracle
SQLALCHEMY_DATABASE_URI = f"oracle+cx_oracle://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}"
# SQLite
SQLALCHEMY_DATABASE_URI = "sqlite://../database.db"
# Postgres
SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}"
.. important::
使用不同的数据库需要安装另外的库,比如 mysql 要安装 pymysql 库(不同平台可能名称不一样),请自行查询资料而后进行配置。
权限效验
------------
在开发后台管理模板的过程中会涉及到权限效验,即访问控制。Pear Admin Flask 中提供了方便的函数用于进行权限效验。详情请查看 :ref:`权限验证模块` 章节。
Schema 序列化
---------------
项目中时常会涉及到数据库的读写,在读入数据时采用 SQLAlchemy,将模型查询的数据对象转化为字典,以此方便与前端页面进行数据交换。
.. important::
Schema 模型放在了 `applications/schemas` 文件夹中,与 `applications/models` 中的数据库模型对应(准确来说是序列化为字典的配置)。
进行序列化时,常常会用到 `applications/common/curd.py` 中的 `model_to_dicts` 函数,下面是一个常见的用法。
.. code-block:: python
from applications.models import Dept
from applications.common import curd
from applications.schemas import DeptSchema
dept = Dept.query.order_by(Dept.sort).all()
power_data = curd.model_to_dicts(schema=DeptSchema, data=dept) # 此处 power_data 将会是一个列表,存储了部门的数据字典
在自己撰写 Schema 模型时,推荐使用自动化类型转化:
.. code-block:: python
from flask_marshmallow.sqla import SQLAlchemyAutoSchema
from applications.models import 你的模型类
class RoleOutSchema(SQLAlchemyAutoSchema):
class Meta:
model = 你的模型类 # table = models.Album.__table__
# include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理
include_fk = True # 序列化阶段是否也一并返回主键
# fields= ["id","name"] # 启动的字段列表
# exclude = ["id","name"] # 排除字段列表
与 layui 的数据格式同步
------------------------------
项目的前端页面基于 layui 框架,在一些数据展示页面(如:layui 动态表格)需要与 layui 框架进行快速的数据交换。比如前端会传入 limit 和 page 参数
用于限定数据展示的范围。故项目中在 SQLAlchemy 中添加了专有的查询函数。详情可以查看文件 `applications/extensions/init_sqlalchemy.py`
下面是对 `Query` 类的解释。
.. class:: Query(BaseQuery)
自定义查询类,扩展了 BaseQuery 的功能,支持软删除、逻辑查询、分页和序列化。
**示例:**
.. code-block:: python
# 软删除
User.query.filter_by(id=1).soft_delete()
# 查询所有未删除的记录
users = User.query.logic_all()
# 分页查询并返回 JSON 数据
data, total, page, per_page = User.query.layui_paginate_json(UserSchema)
.. method:: soft_delete()
软删除当前查询结果集中的记录。
:return: 返回更新操作影响的行数。
.. method:: logic_all()
查询所有未删除的记录。
:return: 返回未删除的记录列表。
.. method:: all_json(schema: Schema)
将查询结果序列化为 JSON 格式。
:param schema: Marshmallow Schema 类。
:return: 返回序列化后的 JSON 数据。
.. method:: layui_paginate(page=None, limit=None)
分页查询,适用于 Layui 表格。
**需要注意的是,如果不提供 page 和 limit 则该函数必须在视图函数中使用,该函数会自动获取 GET 请求中的 limit 和 page 参数构成查询。**
:return: 返回分页对象。
**示例:**
.. code-block:: python
# 查询邮件数据并分页
mail = Mail.query.filter(mf.get_filter(Mail)).layui_paginate()
return model_to_dicts(schema=MailOutSchema, data=mail.items)
.. method:: layui_paginate_json(schema: Schema)
分页查询并返回 JSON 格式数据,适用于 Layui 表格。
:param schema: Marshmallow Schema 类。
:return: 返回包含序列化数据、总数、当前页码和每页条数的元组。
.. method:: layui_paginate_db_json()
分页查询并返回数据库原始数据的 JSON 格式,适用于 Layui 表格。
:return: 返回包含序列化数据和总数的元组。
**示例:**
.. code-block:: python
db.query(User.name).layui_paginate_db_json()
进行字段构造
-----------------------
提炼数据时常常会用到准确匹配或者模糊匹配,又或者是进行多条件大小比较的匹配,此时可以通过字段构造来解决。项目中提供了字段构造的类位于
`applications/common/helper.py` 。详情查看 :ref:`字段构造模块` 章节。
响应合适的响应数据
-----------------------
在进行 JSON 数据响应时,应该注重响应的 JSON 格式类型,一般情况下,项目的 JSON 响应会形如:
.. code-block:: json
{
"code": 0,
"msg": "请求成功",
"data": [],
"count": 0,
"limit": 0
}
其中,`data``total``limit` 字段是可选的,仅在传输数据的时候存在。项目提供了生成统一响应格式的函数,位于 `applications/common/utils/http.py`
详情查看 :ref:`JSON 响应正文生成模块` 章节。
发送硬件
-----------------------
程序提供了发送邮件的模块,前提是需要正确在 `applications/config.py` 中配置 SMTP 服务器。详情查看 ref:`邮件模块` 章节。
.. code-block:: python
from flask_login import current_user
from applications.common.utils import mail
mail.add("test@test.com", "subject", "<h1>Hello</h1>", current_user.id)