Sanic 学习笔记

在这里插入图片描述

Sanic 学习笔记

2023.11.13 - 2023.11.19

学习使用Sanic,浅显的使用上手很快,并创建了一个项目,担心遗忘,特写此文档以记录学习的内容。

环境说明

所用python版本为3.8.12,虚拟环境中安以下包:

名称版本作用安装
python3.11.1语言
mysql8.0.32数据库
sanic23.6.0构建WEB及运行WEB服务pip install 包名
sanic-ext23.6.0sanic扩展^
sanic-auth0.3.0用户验证^
Sanic-CookieSession0.3.1保持用户会话^
sanic-jinja22022.11.11模板引擎^
pymysql1.1.0mysql数据库连接^
cryptography41.0.5密码学包,解决使用mysql 8.0新的加密方式登录时遇到的问题^

具体实现

1.创建项目结构

│ app.py                主程序文件,用于项目启动
├─project               项目文件夹,用于存放项目所需要使用的文件
│      __init__.py      整合项目文件夹下的所有蓝图
│      core.py          用于存放项目共享对象的文件
│      user_bp.py       用户登陆的蓝图
│      home_bp.py       首页蓝图
├─static                静态文件夹
│  ├─css
│  ├─images
│  └─js
└─templates             用于存放html模板的文件夹
   ├─index.html         首页模板
   ├─login.html         用户登陆模板
   └─userlist.html      用户列表模板

Note:根据需要可能会有变化,如可能会增一个用于存放用户上传文件的files文件夹等

2.编辑代码,实现项目功能

(1) app_bp.py文件,主程序
# 导入Sanic类
from sanic import Sanic
# 从project中导入蓝图组p_bp(p_bp定义在__init__.py)
from project import p_bp
# 导入SanicJinja2类
from sanic_jinja2 import SanicJinja2
# 导入sanic_cookiesession
import sanic_cookiesession
# 导入共享的auth实例
from project.core import auth

# 创建Sanic实例app
app = Sanic(__name__)

# 配置静态文件目录
app.static("/static", "./static")

# 以Sanic实例app做为参数,创建SanicJinja2实例jinja
jinja = SanicJinja2(app)

# 配置用户认证login参数为路由login
app.config.AUTH_LOGIN_ENDPOINT = "user.login"

# 配置用户会话保持时间为1小时
app.config.KEEP_ALIVE_TIMEOUT = 3600
app.config.SESSION_COOKIE_SECRET_KEY = "study sanic"

# 加载auth用户认证
auth.setup(app)

# 保持会话
sanic_cookiesession.setup(app)

# 注册蓝图到应用
app.blueprint(p_bp)

if __name__ == "__main__":
    # 全部IP,80端口,调试开,CPU全开,自动重新加载
    app.run(host="0.0.0.0", port=80, debug=True, fast=True, auto_reload=True)
(2) __init__py文件,整合蓝图组
# 导入蓝图类
from sanic import Blueprint
# 导入home_bp中的蓝图实例home
from .home_bp import home
# 导入user_bp中的蓝图实例user
from .user_bp import user

# 定义蓝图组p_bp
p_bp = Blueprint.group(home, user)
(3) core.py文件,共享定义
# 导入pymysql
import pymysql
# 导入Auth实现用户认证
from sanic_auth import Auth

# 这个Auth对象被所有蓝图共享
auth = Auth()

# ------------------- mysql 工具类开始 -------------------
"""
封装一个mysql工具类(需要自己写sql语句)
功能:mysql数据库操作
步骤:
    1.连接数据库
    2.通过连接对象,获取游标对象
    3.增删改查操作
方法:
    1.查
    2.增删改 commit,rollback
"""

# 定义数据库连接参数定义为字典
config = {
    "host": "127.0.0.1",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "charset": "utf8",
    "database": "sanic_test_db",
}

# 定义封装工具类
class MysqlDb:
    # 初始化方法
    def __init__(self):
        # 初始化方法中调用连接数据库方法
        self.conn = self.get_conn()
        # 初始化方法中调用获取游标的方法
        self.cursor = self.get_cursor()

    # 连接数据库的方法
    def get_conn(self):
        # **config代表不定长参数
        conn = pymysql.connect(**config)
        return conn

    # 利用连接对象获取游标对象
    def get_cursor(self):
        """
        1.创建游标对象时加入pymysql.cursors.DictCursor参数,使游标对象返回的查询结果集为字典
        2.在响应返回json数据里加入ensure_ascii=False参数,否则汉字有可能显示为u+数字的形式,例如
            json(result,ensure_ascii=False)
        """
        cursor = self.conn.cursor(pymysql.cursors.DictCursor)
        return cursor

    # 查询sql语句返回所有数据
    def select_all(self, sql):
        self.cursor.execute(sql)
        return self.cursor.fetchall()

    # 查询sql语句返回一条数据
    def select_one(self, sql):
        self.cursor.execute(sql)
        return self.cursor.fetchone()

    # 查询sql语句返回几条数据
    def select_many(self, sql, num):
        self.cursor.execute(sql)
        return self.cursor.fetchmany(num)

    # 增删改除了sql语句不一样,其他都是一样的,都需要提交
    def commit_data(self, sql):
        try:
            # 执行语句
            self.cursor.execute(sql)
            # 提交
            self.conn.commit()
            return 1
        except Exception as e:
            self.conn.rollback()
            return 0

    # 当对象被销毁时,游标要关闭,连接也要关闭
    # 创建时先创建连接后创建游标,关闭时要先关闭游标后关闭连接
    def __del__(self):
        self.cursor.close()
        self.conn.close()
# ------------------- mysql 工具类结束 -------------------

if __name__ == "__main__":
    mydb = Mysqldb()
    sql = "select HEX(uiduser) as uiduser, username, password from sanic_test_db.user;"
    print(mydb.select_all(sql))
(4) home_bp.py文件,首页蓝图
# 导入蓝图类
from sanic import Blueprint
# 导入模板类
from sanic_jinja2 import SanicJinja2
# 导入auth共享实例
from .core import auth

# 创建蓝图对象home
home = Blueprint("home")

@home.route("/home")  # 为蓝图注册路由
@SanicJinja2.template("index.html")  # 使用html文件模板
@auth.login_required  # 用户认证
async def index(request):  # 定义首页路由函数
    result = auth.current_user(request)
    return {"title": result.name}  # 返回数据字典,键名title,值为登陆账号username
(5) user_bp.py文件,用户登陆与查询蓝图
# 导入蓝图类和响应方法
from sanic import Blueprint, response
# 导入模板类
from sanic_jinja2 import SanicJinja2
# 导入自定义的数据库工具类
from .core import MysqlDb
# 导入用户认证实例
from .core import auth
# 导入用户认证User类
from sanic_auth import User

# 定义蓝图user
user = Blueprint("user")

# 定义登陆路由login、加载html模板、声明响应函数login
@user.route("/login", methods=["GET", "POST"])
@SanicJinja2.template("login.html")
async def login(request):
    # 当请求方法为POST
    if request.method == "POST":
        # 从请求表单中取得账户
        username = request.form.get("username")
        # 从请求表单中取得密码
        password = request.form.get("password")
        # 创建数据库工具实例
        mydb = MysqlDb()
        # 构造查询语句
        sql = f"select HEX(uiduser) as uiduser from sanic_test_db.user where username='{username}' and password='{password}';"
        # 调用查询一条数据方法查询数据
        result = mydb.select_one(sql)
        # 如果有查询结果
        if result:
            # 声明用户实例user
            user = User(id=result["uiduser"], name=username)
            # 写入认证对象
            auth.login_user(request, user)
            # 重定向到home
            return response.redirect("/home")
        else:
            # 没有查询结果返回错误信息
            return {"msg": "invalid username or password"}
    elif request.method == "GET":
        # 当请求方法为GET,返回数据为提示输入账号密码
        return {"msg": "please input username & password"}

# 定义用户退出路由logout,声明响应函数logout,并对响应函数进行用户认证
@user.route("/logout")
@auth.login_required
async def logout(request):
    auth.logout_user(request)
    return response.redirect("/login")

# 定义根路由,如已登陆,重定向到home,如未登陆,因有认证转到login
@user.route("/")
@auth.login_required
async def default(request):
    return response.redirect("/home")

@user.route("/user/list")
@auth.login_required
@SanicJinja2.template("userlist.html")
async def user_list(request):
    # 创建数据库工具实例
    mydb = MysqlDb()
    # 构造查询语句
    sql = f"select HEX(uiduser) as uiduser, username, password from sanic_test_db.user;"
    # 调用查询一条数据方法查询数据
    result = mydb.select_all(sql)
    print(result)
    print(type(result))
    # 如果有查询结果
    if result:
        # 返回查询结果
        return {"result": result}
    else:
        # 没有查询结果返回错误信息
        return {"msg": "invalid username or password"}
(6) 数据库、表及添加测试数据
/* 创建名为 sanic_test_db 的mysql数据库,字符集为utf8,排序规则默认 */
CREATE SCHEMA `sanic_test_db` DEFAULT CHARACTER SET utf8 ;
/* 创建user表,用于用户管理 */
CREATE TABLE `sanic_test_db`.`user` (
  `uiduser` BINARY(16) NOT NULL,
  `username` VARCHAR(10) NOT NULL,
  `password` VARCHAR(16) NOT NULL,
  PRIMARY KEY (`uiduser`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COMMENT = '用户表';
/* 添加两条用于测试的记录 */
INSERT INTO `sanic_test_db`.`user`(`uiduser`,`username`,`password`)
VALUES
(UUID_TO_BIN(UUID(),TRUE), 'admin', '1234'),
(UUID_TO_BIN(UUID(),TRUE), 'guest', '1234');
/* 查询测试数据 */
select HEX(uiduser), username, password from sanic_test_db.user;

/* 本机查询结果如下 */
/* 11EE83BB92CB43AD922A2CF05DE219C7	admin	1234 */
/* 11EE83BB92CB5C11922A2CF05DE219C7	guest	1234 */
(7) index.html,首页
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 在title标签中调用传递进来的参数title -->
    <title>{{title}}</title>
</head>

<body>
    <img src="./static/images/sanic_logo.png">
    <h1>wellcome to use Sanic!</h1>
    <a href="/logout">退出登陆</a>
</body>

</html>
(8) login.html,登陆页面
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <form action="/login" method="post">
        账号:<input type="text" name="username" placeholder="请输入用户账号">
        密码:<input type="password" name="password" placeholder="请输入用户密码">
        <input type="submit" value="登陆">
    </form>
    <p style="color: red;">{{msg}}</p>
</body>

</html>
(9) userlist.html,用户列表页
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <table border="1px">
        {% for i in result%}
        <tr>
            <td>{{i.uiduser}}</td>
            <td>{{i.username}}</td>
            <td>{{i.password}}</td>
        </tr>

        {% endfor %}
    </table>
</body>

</html>

Sanic中文网
Sanic-CookieSession
Sanic-Auth
Sanic-Jinja2
cryptography is required for sha256_password or caching_sh 解决办法
python操作mysql

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值