【自学开发之旅】Flask-标准化返回-连接数据库-分表-orm-migrate-增删改查(三)

news2024/11/26 4:46:02

业务逻辑不能用http状态码判断,应该有自己的逻辑判断。想要前端需要判断(好多if…else),所以需要标准化,标准化返回。
json标准化返回:
最外面:data,message,code三个字段。
data:返回的数据
code:应用状态码:先设计好,成功-0,失败–登录失败1,注册失败2
msg:返回的说明
我们写的接口也要按照这个格式来

添加libs/response.py

def generate_response(data = None, msg = "success!", code = 10000):
    # 约定返回的数据格式
    if data is None:
        data = []

    return {
        "code": code,
        "msg": msg,
        "data": data
    }

然后修改返回:
login.py

from flask import Blueprint, request
from config.settings import user_dict
from libs.response import generate_response

login_bp = Blueprint("login_bp", __name__, url_prefix="/v1")

@login_bp.route("login")
def login():
    user = request.json.get("username")
    passwd = request.json.get("passwd")
    local_user_passwd = user_dict.get(user)
    if local_user_passwd and passwd == local_user_passwd:
        return generate_response(msg="success")
    return generate_response(msg="login fail!", code=10001)

register.py

from flask import Blueprint, request
from config.settings import user_dict
from libs.response import generate_response

register_bp = Blueprint("register_bp", __name__, url_prefix="/v1")

@register_bp.route("register")
def register():
    username = request.json.get("username")
    passwd = request.json.get("passwd")
    re_passwd = request.json.get("re_passwd")
    if not (username and passwd and re_passwd):
        return generate_response(msg="参数传递不完整", code=3)
    elif passwd != re_passwd:
        return generate_response(msg="注册密码不一致", code=2)
    elif username in user_dict:
        return generate_response(msg="用户已注册",code=1)
    else:
        user_dict[username] = passwd
        print(f"user_dict is {user_dict}")
        return generate_response(msg="register success!", code=10000)

连接数据库(为了避免频繁的打开关闭消耗过多资源)

libs/conn_mysql.py

import pymysql
from config.settings import DB_PASS, DB_PORT, DB_SCHEM, DB_USER, DB_HOST


def conn_mysql():
    conn = pymysql.connect(
        host = DB_HOST,
        port = DB_PORT,
        user = DB_USER,
        password = DB_PASS,
        db = DB_SCHEM
    )
    return conn

为了只连一次,绑到app上
app.py添加:
上面返回了一个连接对象conn,把他作为一个属性交给了sq_app对象,再给sq_app对象随意的可以设置属性,自己定义(mysql_db)。所以把连接交给了app。

def create_app():
	#连接数据库
    sq_app.mysql_db = conn_mysql()

刚好flask提供了一个current_app,在你请求过来的时候,会把你当前的app的上下文内容放在current_app里。
router/product_view/product.py

from . import product_bp
from flask import current_app
from libs.response import generate_response

@product_bp.route("/product/get")
def get_product():
    # import pymysql

    # db = pymysql.connect(host='192.168.1.150',
    #                      user='jiangda97',
    #                      password='Jiangda123#',
    #                      database='sq-flask')
    cursor = current_app.mysql_db.cursor()
    cursor.execute("select * from product_info")
    data = cursor.fetchall()
    print(data)
    # db.close()
    if data:
        return generate_response(data=data, msg="get product info success!")
    else:
        return generate_response(msg="get data empty", code = 4)

router/product_view/__init__.py

from flask import Blueprint
product_bp = Blueprint("product_bp", __name__, url_prefix="/v1")

from . import product

分表
优点:节省空间,避免数据不必要的膨胀。
缺点:

新增了一个product_kind_table表

select product_info.product_id, product_info.product_name, product_kind_table.kind, product_info.product_price, product_info.product_address
from product_info inner join product_kind_table
on product_kind = id
where product_id = 1

在这里插入图片描述
修改代码router/product_view/product.py

    # 通过url携带参数来传递id
    id = request.args.get("id")
    if id is None:
        sql_str = f"select product_info.product_id, product_info.product_name, product_kind_table.kind, product_info.product_price, product_info.product_address \
                    from product_info inner join product_kind_table \
                    on product_kind = id\
                    where product_id = {id}"
    else:
        sql_str = f"select product_info.product_id, product_info.product_name, product_kind_table.kind, product_info.product_price, product_info.product_address \
                    from product_info inner join product_kind_table \
                    on product_kind = id\
                    where product_id = {id}"

    cursor = current_app.mysql_db.cursor()
    cursor.execute(sql_str)
    data = cursor.fetchall()
    # print(data)
    # db.close ()
    if data:
        return generate_response(data=data, msg="get product info success!")
    else:
        return generate_response(msg="get data empty", code = 4)

在这里插入图片描述

ORM

object relation mapping对象关系映射
请添加图片描述
orm对象持久化对象

数据库的表 – 类

表中的字段 – 属性

一行行记录 – 对象

models/__init__.py

from flask_sqlalchemy import SQLAlchemy

#生成对象映射实例(db就是我们的中间层)
db = SQLAlchemy()

def init_app_db(app):
    db.init_app(app)

models/product.py

from . import db

class ProductInfo(db.Model):
    __tablename__ = "product_info"
    product_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    product_name = db.Column(db.String(256))
    product_kind = db.Column(db.Integer)
    product_price = db.Column(db.Float)
    product_address = db.Column(db.String(128))

都得运行:init文件添加from . import product

绑定到核心对象:app.py文件添加

    import models
    models.init_app_db(sq_app)

最后运行报错:

RuntimeError: Either ‘SQLALCHEMY_DATABASE_URI’ or ‘SQLALCHEMY_BINDS’
must be set.

意思是需要设置这两个变量,即orm映射的数据库信息。

config/settings.py添加

SQLALCHEMY_DATABASE_URI = "mysql+pymysql://jiangda97:Jiangda123#@192.168.1.150:3306/sq-flask"

之前我们在app.py将settings都读入sq_app.config里了,且是都大写的key。
刚好我们的SQLAchemy底层就是会自动读取sq_app.config里的关于连接数据库的操作。

SQLALCHEMY_DATABASE_URI = “mysql+pymysql://jiangda97:Jiangda123#@192.168.1.150:3306/sq-flask”
底层+用的连接方式://用户名:密码@host:port/数据库名

然后我们准备用它来完成一个增加操作,在router/product_view/product.py

from models.product import ProductInfo
from models import db

# 新增数据库记录
@product_bp.route("/product/add", methods=['POST'])
def product_add():
    # 接收客户端的传递
    pro_name = request.json.get("proname")
    pro_kind = request.json.get("prokind")
    pro_price = request.json.get("proprice")
    pro_address = request.json.get("proadd")

    # 实例化类成对象
    proinfo = ProductInfo()
    # 设置属性
    proinfo.product_name = pro_name
    proinfo.product_kind = pro_kind
    proinfo.product_price = pro_price
    proinfo.product_address = pro_address

	# 实例化并设置属性也可以这么写
    # proinfo = ProductInfo(product_name = pro_name,
    #                       product_kind = pro_kind,
    #                       product_price = pro_price,
    #                       product_address = pro_address)
  
    # 生效到数据库
    db.session.add(proinfo)
    db.session.commit()

    return generate_response(msg="add success!")

在这里插入图片描述

migrate

添加models/product.py
在该类下

    add_time = db.Column(db.DateTime, default=datetime.datetime.now())

数据库迁移工具,版本管理 – flask-migrate

改server.py

# 数据库迁移工具,版本管理 -- flask-migrate
from flask_migrate import Migrate
from models import db

migrate = Migrate(sq_app, db)

if __name__ == '__main__':
    sq_app.run(host = sq_app.config['HOST'],
               port = sq_app.config['PORT'],
               debug = sq_app.config['DEBUG'])

方便开发,不改变应用逻辑,只是方便我们把orm映射的类,这个添加的字段生效到数据库,不需要自己修改数据库了。

terminal中输入该命令,(在命令行操控flask – flask cli)

(venv) D:\sq-flask>flask --app server:sq_app db init
Creating directory 'D:\\sq-flask\\migrations' ...  done
Creating directory 'D:\\sq-flask\\migrations\\versions' ...  done
Generating D:\sq-flask\migrations\alembic.ini ...  done
Generating D:\sq-flask\migrations\env.py ...  done
Generating D:\sq-flask\migrations\README ...  done
Generating D:\sq-flask\migrations\script.py.mako ...  done
Please edit configuration/connection/logging settings in 'D:\\sq-flask\\migrations\\alembic.ini' befor
e proceeding.

然后就会产生一个migrations的文件夹
在这里插入图片描述
migrate单独用不了,借助flask cli命令行工具,migrate绑定好app后,自动创建好db命令。
初始化flask --app server:sq_app db init

–app 指定运行哪个app
初始化会创建migrations的文件夹

可以随时删,再init,做了修改,提交版本!

(venv) D:\sq-flask>flask --app server:sq_app db migrate -m "add time"
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected removed table 'product_kind_table'
INFO  [alembic.autogenerate.compare] Detected added column 'product_info.add_time'
INFO  [alembic.autogenerate.compare] Detected NULL on column 'product_info.product_name'
INFO  [alembic.autogenerate.compare] Detected NULL on column 'product_info.product_kind'
INFO  [alembic.autogenerate.compare] Detected NULL on column 'product_info.product_price'
INFO  [alembic.autogenerate.compare] Detected NULL on column 'product_info.product_address'
Generating D:\衡山\2023-文老师\sq-flask\migrations\versions\43aac3b3bb51_add_time.py ...  done

upgrade就可以生效了

(venv) D:\sq-flask>flask --app server:sq_app db upgrade
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 43aac3b3bb51, add time


在这里插入图片描述
严格按照orm定义好的模型,保持数据库和模型一致,如果数据库有,orm定义的模型没有,则会把数据库多出来的删掉。

回退:flask --app server:sq_app db downgrade

命令行进入上下文环境:(用来测试调试代码)
flask --app server:sq_app shell

(venv) D:\sq-flask>flask --app server:sq_app shell
Python 3.9.1 (tags/v3.9.1:1e5d33e, Dec  7 2020, 17:08:21) [MSC v.1927 64 bit (AMD64)] on win32
App: app
Instance: D:\sq-flask\instance
>>> from models.product import ProductInfo
>>> p1 = ProductInfo()
>>> p1.product_name = "3333"
>>> p1.product_kind =  2
>>> p1.product_price = 22
>>> p1.product_address = "山东"
>>> from models import db
>>> db.session.add(p1)
>>> db.session.commit()
>>>

查询和修改:
修改其属性。

>>> p2 = ProductInfo.query.get(3)
>>> p2
<ProductInfo 3>
>>> dir(p2)
['__abstract__', '__annotations__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__for
mat__', '__fsa__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__',
'__lt__', '__mapper__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__
', '__sizeof__', '__str__', '__subclasshook__', '__table__', '__tablename__', '__weakref__', '_sa_class_manager',
'_sa_instance_state', '_sa_registry', 'add_time', 'metadata', 'product_address', 'product_id', 'product_kind', 'pr
oduct_name', 'product_price', 'query', 'query_class', 'registry']
>>> p2.product_name
'牛肉'
>>> p2.product_name = "牛肌肉"
>>> db.session.add(p2)
>>> db.session.commit()
>>>

删除:

>>> p3 = ProductInfo.query.get(4)
>>> db.session.delete(p3)
>>> db.session.commit()

综合:id通过url携带参数传递,完成修改和删除
删除:/product/modify – PUT
删除:/product/delete – DELETE

router/product_view/product.py

@product_bp.route("/product/modify", methods=['PUT'])
def product_modify():
    # 接收客户端的传递携带的参数
    id = request.args.get("id")
    p1 = ProductInfo.query.get(id)
    if p1:
        # 接收客户端的传递
        pro_name = request.json.get("proname")
        pro_kind = request.json.get("prokind")
        pro_price = request.json.get("proprice")
        pro_address = request.json.get("proadd")

        p1.product_name = pro_name
        p1.product_kind = pro_kind
        p1.product_price = pro_price
        p1.product_address = pro_address

        db.session.add(p1)
        db.session.commit()
        return generate_response(msg="modify success!")
    else:
        return generate_response(msg="no such product!", code=5)

修改:尽管你修改一个,但你提交的时候得提交全部的字段

删除:

@product_bp.route("/product/delete", methods=['DELETE'])
def product_delete():
    id = request.args.get("id")
    p2 = ProductInfo.query.get(id)
    if p2:
        db.session.delete(p2)
        db.session.commit()
        return generate_response(msg="delete success")
    else:
        return generate_response(msg="no such product", code=6)

查询:
query.get() 一般用来查询主键
query.all() 查询所有(列表类型)

>>> ProductInfo.query.filter_by(product_kind=1).all()
[<ProductInfo 1>, <ProductInfo 2>]

>>> ProductInfo.query.filter(ProductInfo.product_kind == 1).all()
[<ProductInfo 1>, <ProductInfo 2>]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/993320.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Unity基础】2.网格材质贴图与资源打包

【Unity基础】2.网格材质贴图与资源打包 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity基础系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;网格材质纹理 第一次接触3D物体的话&#xff0c;会觉得好神奇啊&#xff0c;这个物体究竟是由什么组…

教育志愿者的初心与担当

近日&#xff0c;有报道显示&#xff0c;在全球范围内&#xff0c;大约有6000万的儿童由于各种原因无法接受基础教育&#xff0c;其中非洲大陆的教育贫瘠现象尤为显著。然而&#xff0c;在这片土地上&#xff0c;有一位中国年轻志愿者Lily Zhu&#xff0c;以一种富有创新精神的…

Mysql中in和exists的区别 not in、not exists、left join的相互转换

文章目录 1. in 介绍1.1 in中数据量的限制1.2 null值不参与in或not in&#xff0c;也就是说in and not in 并不是全量值&#xff0c;排除了null值1.3 in的执行逻辑 2. exists介绍2.1 exists not exists 是全量数据2.2 exists的执行逻辑 3. 小表驱动大表的好处4. in、not in、e…

图像噪声--添加噪声

椒盐噪声 椒盐噪声就是给图片添加黑白噪点&#xff0c;椒指的是黑色的噪点(0,0,0),盐指的是白色的噪点(255,255,255)&#xff0c;通过num来控制噪声多少&#xff0c;值越大添加的噪声越多&#xff0c;图像损坏的更加严重。 void add_salt_pepper_noise(Mat& src,Mat& …

Mojo-SDK详细安装教程

Mojo-SDK安装 运行环境&#xff1a;windows11wsl2&#xff08;ubuntu1804&#xff09; 截至20230909&#xff0c;windows,mac系统暂时不支持 step1: Install VS Code, the WSL extension, and the Mojo extension. step2: Install Ubuntu 22.04 for WSL and open it. step…

Vue el-table 重置按钮设计模板

vue 文件演示模板 <template><el-button icon"el-icon-refresh" size"large" click"resetFunction">重置</el-button><el-tableheight"450"v-loading"loading":data"dataList":row-key&quo…

U盘插上就让格式化是坏了吗?数据怎么恢复

U盘插上就让格式化是坏了吗&#xff1f;当您遇到U盘插上后提示需要格式化的情况时&#xff0c;不要慌张。这种情况并不一定意味着U盘已经坏了。下面我们一起来了解下如何恢复里面的数据&#xff0c;并解决U盘提示格式化的问题。 U盘一插上就提示格式化是什么原因 许多人可能会有…

个人微信多账号聚合管理如何实现?

在日常工作中&#xff0c;您是否会遇到以下问题&#xff1a; 微信号多&#xff0c;需反复切换设备及账号&#xff0c;工作效率低。 无法快速响应客户消息&#xff0c;客户体验感差。 无法随时掌握员工与客户沟通情况&#xff0c;员工沟通质量难以控制&#xff0c;管理难。 员…

Spring系列文章:面向切面编程AOP

一、代理模式 1、代理模式使用场景引入 ⽣活场景1&#xff1a;⽜村的⽜⼆看上了隔壁村⼩花&#xff0c;⽜⼆不好意思直接找⼩花&#xff0c;于是⽜⼆找来了媒婆王妈妈。这 ⾥⾯就有⼀个⾮常典型的代理模式。⽜⼆不能和⼩花直接对接&#xff0c;只能找⼀个中间⼈。其中王妈妈是…

OpenCV 11(图像金字塔)

一、 图像金字塔 **图像金字塔**是图像中多尺度表达的一种&#xff0c;最主要用于图像的分割&#xff0c;是一种以多分辨率来解释图像的有效但概念简单的结构。简单来说, 图像金字塔是同一图像不同分辨率的子图集合. 图像金字塔最初用于机器视觉和图像压缩。其通过梯次向下采…

shell知识点复习

1、shell能做什么&#xff08; Shell可以做任何事(一切取决于业务需求) &#xff09; 自动化批量系统初始化程序 自动化批量软件部署程序 应用管理程序 日志分析处理程序 自动化备份恢复程序 自动化管理程序 自动化信息采集及监控程序 配合Zabbix信息采集 自动化扩容 2、获取当…

淘宝双11数据分析与预测课程案例中(林子雨)错误点总结

问题一&#xff1a;可视化代码中男女买家各个年龄段对比散点图中数值不显示以及坐标不正确问题如下图 解决方法&#xff1a; 1修改坐标 2修改数值 修改后散点图 问题二&#xff1a;各省份的总成交量对比中地图显示不出来 有时间再写

海量小文件传输对于企业选用文件传输软件的重要意义

在当前的商业环境中&#xff0c;数据具有极其重要的作用&#xff0c;是企业竞争的核心要素。随着互联网、物联网和云计算等技术的快速发展&#xff0c;数据的类型和规模变得越来越多样。在这其中&#xff0c;海量小文件作为一种普遍而重要的数据形式&#xff0c;扮演着连接信息…

新知同享 | Mobile 开发轻松跨屏,高效构建

谷歌致力于帮助开发者 更快、更轻松地打造高质量的移动体验 一起来看 2023 Google 开发者大会上 Mobile 开发值得重点关注的成果与更新 了解如何提高平台及应用质量 提升开发效率 使多设备开发体验更流畅 实现轻松跨屏&#xff0c;高效构建 精彩大会现场一览 用户对跨屏幕体验…

在k8s中创建ConfigMap的四种方式与初识helm包管理工具

非敏感数据&#xff0c;比如应用的配置信息&#xff0c;则可以用ConfigMap 创建configmap四种方式 &#xff08;1&#xff09;通过--from-literal&#xff1a; kubectl create configmap myconfigmap --from-literalconfig1xxx --from-literalconfig2yyy 每个--from-literal…

Revit SDK 介绍:Ribbon 界面

前言 Revit 通过 API 将完整的 Ribbon 做了保留&#xff0c;同时这些菜单按钮也可以和相应的命令绑定。 内容 运行效果如下所示&#xff1a; 菜单特写&#xff1a; Ribbon Sample 整体是 API 暴露出来的一个 RibbonPanel&#xff0c;对应的接口&#xff1a; namespace Au…

dll文件反编译源代码 C#反编译 dotpeek反编译dll文件后export

目录 背景下载安装dotpeek导入dll文件export导出文件参考 背景 项目合作的时候&#xff0c;使用前人的或者其他部门dll文件直接在机台运行&#xff0c;会出现很多问题&#xff0c;逻辑&#xff0c;效率等等&#xff0c;此时我们可以选择对他们的代码进行反编译和重构&#xff…

递归算法学习——被围绕的区域,太平洋大西洋流水问题

目录 ​编辑 一&#xff0c;被围绕的区域 1.题意 2.解释 3.题目接口 4.解题思路及代码 二&#xff0c;太平洋大西洋流水问题 1.题意 2.解释 3.题目接口 4.解题思路及代码 一&#xff0c;被围绕的区域 1.题意 给你一个 m x n 的矩阵 board &#xff0c;由若干字符 X 和…

对卷积的一点具象化理解

前言 卷积的公式一般被表示为下式&#xff1a; 对新手来说完全看不懂这是干什么&#xff0c;这个问题需要结合卷积的应用场景来说。 原理 卷积比较广泛的应用是在信号与系统中&#xff0c;所以有些公式的定义会按照信息流的习惯。假设存在一串信号g(x)经过一个响应h(x)时他的响…

高云USB下载器仿真器用户手册(包括在线逻辑分析仪的使用方法)

高云 USB 仿真器用户手册 一.简介 仿真器用于高云 GOWIN 公司所生产的 FPGA&#xff0c;可用于程序下载和调试。主要特点如下&#xff1a; 1.支持宽电压1.2V - 3.6V&#xff1b; 2.速度最高可达30Mb/s&#xff0c;极速完成下载和波形调试功能&#xff1b; 3.完美支持在线逻…