flask sqlalchemy 数据动态更新

coding时候用flask sqlalchemy操作数据库,但是由于了解的不是很多,因此一直卡在数据动态更新上。后来总算是解决了这个问题,记录下大致过程。

本文假设有两张表格需要操作,一个是group,一个是student。

group
字段名称类型示例值
id编号int自增主键12
name班级名称varchar(255)非空计科23(1)
parent_id父级组织编号int指向group.id的外键5
leaf叶节点tinyint非空,默认值为00
student
字段名称类型示例值
id编号int自增主键6
stu_id学生学号varchar(255)非空2023xxxxxxxxx
name学生名称varchar(255)非空张XX
group_id所属组织idint指向group.id的外键5
telephone学生电话varchar(255)非空5

用datagrip展示ER图如下:

两张表格对应的flask sqlalchemy代码如下:

from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import remote
import sqlalchemy

database = SQLAlchemy()

class Group(database.Model):
    __tablename__ = 'group'

    id = database.Column(database.Integer, primary_key=True, comment='自增id')
    group_id = database.Column(database.Integer, nullable=False, unique=True, comment='组织id')
    name = database.Column(database.String(255), nullable=False, comment='组织名称')
    parent_id = database.Column(database.ForeignKey('group.group_id', ondelete='CASCADE', onupdate='CASCADE'), nullable=False, index=True, comment='上级组织id')
    leaf = database.Column(database.TINYINT, nullable=False, comment='是否为叶节点')

    parent = database.relationship('Group', remote(sqlalchemy.column('group.id')))

class Student(database.Model):
    __tablename__ = 'student'

    id = database.Column(database.Integer, primary_key=True, comment='自增id')
    stu_id = database.Column(database.String(255), nullable=False, unique=True, comment='学生学号')
    name = database.Column(database.String(255), nullable=False, comment='学生姓名')
    group_id = database.Column(database.ForeignKey('group.group_id', ondelete='CASCADE', onupdate='CASCADE'), nullable=False, index=True, comment='学生所在组织id')
    telephone = database.Column(database.String(255), nullable=False, comment='学生电话')

    group = database.relationship('Group')

普通情况下,用以下方法添加一条数据:

obj = Group(name=val_1,parent_id=val_2,leaf=val_3)
database.session.add(obj)
database.session.commit()

但是直接使用类进行添加有缺陷。特别对于表格中字段数量较多的时候,这一条语句会非常长,显得不灵活,且泛用性不是特别强。

因此思考是否有一种办法,能够根据传入的字典,动态增加数据。搜索似乎也没能找到想要的答案,于是乎尝试自己改,碰壁+踩坑无数,终于改出了一个满意的答案。

在flask-sqlalchemy中,ORM是个非常重要的概念。

对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术ORM框架是连接数据库的桥梁,只要提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。

基于此,给出如下代码:(把用户名和密码改成本机数据库的用户名和密码、表格内容替换成自定义的表格)

class DBCtrl:
    def __init__(self,host,username,password,db,table):
        """
        初始化
        :param host: 连接ip
        :param username: 用户名
        :param password: 密码
        :param db: 数据库名称
        :param table: 表的名称
        """
        self.host = host
        self.username = username
        self.password = password
        self.db = db
        self.table = table
        self.model = Group if self.table=='group' else Student

        self.engine = create_engine('mysql+pymysql://' + self.username + ':' + self.password + '@' + self.host + ':3306/' + self.db)
        self.metadata = MetaData()
        self.metadata.bind = self.engine
        self.Base = sqlalchemy.orm.declarative_base()
        self.create_not_exist()

    def create_not_exist(self):
        """
        如果表不存在则创建
        """
        exist = self.engine.dialect.has_table(db.engine.connect(),schema=self.db,table_name=self.table)
        if not exist:
            db.create_all()
        class CtrlTable(self.Base,db.Model):
            __table__ = Table(self.table,self.metadata,autoload_with=self.engine)

            def __init__(self,data_dict):
                for key, value in data_dict.items():
                    setattr(self, key, value)
        self.CtrlTable = CtrlTable


    def update_dynamic(self,session,value_dic_list,logger):
        """
        动态更新,如果存在则更新,不存在则插入,可执行批量数据
        :param session: 数据库会话
        :param value_dic_list: 需要更新或增加数据的列表
        :param logger: 日志,类型为logging
        """
        for vd in value_dic_list:
            try:
                query = self.CtrlTable(vd)
                session.add(query)
                session.commit()
            except sqlalchemy.exc.OperationalError as seo:
                logger.debug("故障:"+str(seo))
            except sqlalchemy.exc.IntegrityError as sei:
                logger.debug("故障:"+str(sei))
            except sqlalchemy.exc.PendingRollbackError as sep:
                logger.debug("故障:"+str(sep))        

代码设定所有的flask-sqlalchemy代码都存放在一个类中方便操作数据库,通过实例化这个操作的类,自动导入或创建表格,并在类中定义了CRUD操作。上述代码中给出了增加和修改操作。我在代码中合并了增加和更改操作为update_dynamic,如果记录不存在则增加,存在则进行修改。

代码中的self.CtrlTable是一个Table类,根据传入的表名从数据库导入对应表。重写构造函数,以便传入字典增加或修改记录。python中通过setattr函数可以设置类的属性,如果属性存在,则修改该值,如果属性不存在,则设定该值。

因此,如果希望灵活批量添加或者修改记录,以'group'表为例,用一个字典存放一条记录vd

{
    'group_id'='SC_01',
    'name'='xxxx大学',
    'parent_id'=None,
    'leaf'=False
}

列表value_dic_list存放多个记录:前两条为增加的数据,最后一条为修改的数据

[
    {
    'group_id'='SC_02',
    'name'='xxxx大学',
    'parent_id'=None,
    'leaf'=False
    },
    {
    'group_id'='CO_03',
    'name'='xxxx学院',
    'parent_id'='SC_02',
    'leaf'=False
    },
    {
    'group_id'='CO_02',
    'name'='xxx学院'
    }
]

数据库原始数据如下:

将上述作为输入传入update_dynamic函数,运行得到:

其中红色部分为修改内容,橙色部分为新增内容。

需要注意的是,用上述类实例化并进行操作时,确保在flask路由函数的环境下,否则报错。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值