docker版jxTMS使用指南:python服务之ORM操作数据库

本文讲解4.0版jxTMS中python服务的ORM能力,整个系列的文章请查看:docker版jxTMS使用指南:4.0版升级内容

docker版本的使用,请参考:docker版jxTMS使用指南

jxTMS通过jxMysql模块提供了对mysql的ORM形式的访问,使得python服务扩展中访问mysql数据库非常简单。

引用:

from jx.jxMysql import ORM

为便于说明,先展示一个实际的数据类,位于app目录下的data_vrs20.py中的VRS20Data:

dbName = jxGo.getSysConfig('dbName')

class VRS20Data(ORM):
    _ormAttr = {
        'ID':'int',
        'CreateTime':'datetime',
        'DevID':'int',
        'Ranges':'string',
        'Level':'string',
        'Unit':'string',
        'Status':'string',
        'SD':'string'
    }
    _key = ['ID']
    _excludeReset = ['DevID']
    def __init__(self,data=None):
	    #data是初始化数据,即使用data来初始化本数据对象
        super(VRS20Data , self).__init__(dbName,'VRS20Data',data=data)

继承ORM的类实质上就对应数据库中的一个数据表【最好类表同名】。该数据表应先在jxTMS的data文件中定义,然后通过热机刷新来自动创建。数据表必须放入到具体的数据库中,所以一般应先了解清楚需要访问的组织别名,然后在配置文件中添加系统配置dbName。然后在数据类定义前就执行:

dbName = jxGo.getSysConfig('dbName')

继承自ORM的数据类可以定义三种类属性

1、_ormAttr

数据表的各数据列,应和data文件中的同名数据类一一对应。

注:如果少定义了数据列,不影响读取以及update操作,但无法insert新的数据行。这是由于jxTMS根据data文件中数据类的定义创建数据表时会自动将各列创建为Not Null

一般来说,jxTMS中的数据类都有Long型的ID和日期形式的CreateTime,如果定义了这两个属性,ORM会在生成数据对象时自动调用jxUtils中的CID和Now来初始化两属性。

2、_key

数据表的主键,可以有多个,即联合主键。

注:如果不定义key,则update时会掷出异常拒绝执行,因为没有用主键来设置where字句的update语句,一旦执行就会将整个表的所有行修改为相同的数据

3、_excludeReset

日志、需连续保存的设备实时数据等,有些字段是不需要更新的,如日志的对象、数据所属于的设备ID等,所以就没必要每次生成全新的ORM对象,只要reset一下再写入新值即可。而excludeReset指示reset时哪些字段不需要清除,reset时就不会清除这些字段了。

和之前的jxTMS的python服务基础类不同,ORM既定义了类函数也定义了对象函数。

ORM类函数

register(cls, clsName, ormCls)

注册数据类

参数:
	 clsName:数据类名
	 ormCls:相应的数据类
返回值:
	无
示例:
	#定义完VRS20Data后,执行
	ORM.register('VRS20Data',VRS20Data)
说明:
	getBy、listBy、searchBy三个类查询语句是定义在ORM类中的,所以想使用这些函数来查询ORM派生出来的数据类就必须先注册这些数据类

virtual(cls,bv)

在执行insert、update操作时只在日志中打印sql语句而不实际执行

参数:
	bv:是否开启全局virtual功能
返回值:
	无
说明:
	主要用于初始阶段的调试,以避免插入太过乱七八糟的数据,导致查询功能混乱

debug(cls,bv)

在执行数据库访问时在日志中打印sql语句

参数:
	bv:是否开启全局debug功能
返回值:
	无
说明:
	开启后,在执行getBy、getByID、listBy、searchBy、insert、update这六个函数时都将打印要执行的sql语句

virtual和debug都是全局性影响,即只要打开,所有ORM操作都受影响,所以一般只用于调试阶段。

getBy(cls,dbName,clsName,attr,value)

根据属性attr的值从clsName表中读取一行,并转换为dict数据返回

参数:
	dbName:数据库名
	clsName:数据类名,也即要查询的数据表名,必须使用register注册过
	attr:该数据类在_ormAttr中定义的属性,如果不是会掷出异常
	value:想查询的数据对象的属性值
返回值:
	result:符合条件的数据行,转换为dict。如果有多个符合条件的行,则只会返回一个,具体返回哪个无法确定
	rc:执行是否成功
示例:
	rs,rc = ORM.getBy(dbName,'VRS20Data','DevID',123456)
	if rc:
		...

注:所有对数据库的增删改查操作,返回的都是(result,rc)

getByID(cls,dbName,clsName,id)

根据id值从clsName表中读取一行,并转换为dict数据返回

参数:
	dbName:数据库名
	clsName:数据类名,也即要查询的数据表名
	id:数据对象的id值,整数
返回值:
	result:符合条件的数据行,转换为dict
	rc:执行是否成功

listBy(cls,dbName,clsName,attr,value,limit=15,offset=0)

根据属性attr的值从clsName表中读取所有符合条件的行,并转换为dict数据的list返回

参数:
	dbName:数据库名
	clsName:数据类名,也即要查询的数据表名
	attr:该数据类在_ormAttr中定义的属性,如果不是会掷出异常
	value:想查询的数据对象的属性值
	limit:一次最多查出多少行,默认15行,尽量不要设的太大
	offset:从哪一行开始取出
返回值:
	result:符合条件的所有数据行,转换为由dict组成的list
	rc:执行是否成功

**searchBy(cls,dbName,clsName,*args,kw)

和listBy类似,但可以一次性指定多个查询条件

参数:
	dbName:数据库名
	clsName:数据类名,也即要查询的数据表名
	args:忽略
	kw:key=value的键-值对,key要么是limit或offset,要么是在_ormAttr中定义的属性
返回值:
	result:符合条件的所有数据行,转换为由dict组成的list
	rc:执行是否成功
说明:
	limit默认是15、offset默认是0
示例:
	#查询VRS20Data中指定dev的数据,一次最多三条,从符合条件的0行开始读取
	rs,rc = ORM.searchBy('demoOrg_2255','VRS20Data',DevID=123456789,limit=3)
	#查询VRS20Data中指定Level的数据,一次最多15条,从符合条件的7行开始读取
	rs,rc = ORM.searchBy('demoOrg_2255','VRS20Data',Level='随便指定的数',offset=7)
	#查询VRS20Data中指定dev和Level的数据,一次最多15条,从符合条件的0行开始读取
	rs,rc = ORM.searchBy('demoOrg_2255','VRS20Data',DevID=123456789,Level='xxx')

注:直接使用searchBy较为繁琐,所以jxTMS特意提供了其可迭代的封装格式:searchIter

searchIter

searchIter是searchBy的可迭代的封装,即支持for循环。其定义为:

class searchIter:
    def __init__(self,dbname,clsName,limit=15):
        #dbname:数据库名
        #clsName:数据表名
        #limit:一次最大查询行数
	
    def total(self):
        #返回符合条件的总行数
	    
    def limit(self):
        #返回一次查询的最大行数
	    
    def offset(self):
        #返回待查询的下一个数据序号
		#list或for如果触发数据库查询,则从哪一个序号开始从数据库中查询
		#以limit为步进,如:0,15,30,45,...
    
    def nextOrder(self):
        #仅用于for循环遍历
        #返回下一个将被for循环读取的数据序号
		#以1为步进,如:1,2,3,4,...

    def reset(self):
        #重置,可再次遍历

    def condition(self,*args,**kw):
        #设置查询条件
        #args:忽略
        #kw:key=valu形式的查询条件组

    def list(self, offset=None):
        #手动执行一次查询并获得查询结果列表
        #offset:如果不为None则从此处开始查询,一次查询最多limit条

一般使用for来使用searchIter。示例:

from jx.jxMysql import searchIter
import app.data_vrs20

dbName = jxGo.getSysConfig('dbName')

s = searchIter(dbName,'VRS20Data')
#设置查询条件
s.condition(Status='007')
print(s.total())

for vd in s:
    print(s.nextOrder())
    print(vd)
    
#再查一次
s.reset()
n = s.total()
i = s.offset()
while i < n:
    rs = s.list(offset=i)
    print(rs)
    i = i + s.limit()

需要注意的是,如果符合条件的数据非常多,直接用for来遍历是非常恐怖的,这也是为什么要提供list函数的原因,因为其可以配合分页来使用。

注:searchIter只能查询单表,所以更新版本的jxMysql增加了多表联合查询,会合并到下一版本中发布

ORM的对象函数

数据对象的初始化

创建一个继承自ORM的数据对象时,会自动初始化ID和CreateTime,如果该数据类定义了这两个属性的话。

ORM的对象初始化函数为:

def __init__(self,dbname,dbtable,data=None):
    ...

data是一个dict,如果送入,则会用其来初始化ORM对象。

所以VRS20Data的初始化函数就是:

def __init__(self,data=None):
	#指示本数据对象访问的是dbName库的VRS20Data表
	super(VRS20Data , self).__init__(dbName,'VRS20Data',data=data)

data(self)

返回初始化时送入的dict

参数:
	无
返回值:
	初始化时送入的dict

**set(self,*args,kw)

设置属性值

参数:
	args:忽略
	kw:key=value的键-值对,key应是在_ormAttr中定义的属性
返回值:
	对象自身
示例:
	#设置DevID和Level
	do.set(DevID=123456789,Level='xxx').update()

reset(self)

重新初始化

参数:
	无
返回值:
	对象自身
说明:
	reset包含两个步骤:
	1、除了在_excludeReset中指定的属性,其它属性全部被清除
	2、重新初始化,重置ID和CreateTime
示例:
	#重置后设置Level,ID是新的,所以是插入
	do.reset().set(Level='xxx').insert()

insert(self)

将本数据对象插入到数据库中

参数:
	无
返回值:
	对象自身
说明:
	如果某属性未赋值,会自动插入其默认值
示例:
	do = VRS20Data()
	do.set(DevID=123456789,Level='xxx').insert()

update(self)

将修改后的本数据对象更新到数据库中

参数:
	无
返回值:
	对象自身
说明:
	根据key来修改指定的对象
示例:
	#读取数据
	dict,rc = ORM.getBy(dbName,'VRS20Data','Level','xx')
	if rc:
		#用读取到的数据创建数据对象
		do = VRS20Data(data=dict)
		#修改后保存到数据库中
		do.set(DevID=123456789,Level='xxx').update()

getInfoValue(self,vn)

读取json格式的Info属性对应的dict中的vn名的值

参数:
	vn:Info属性的dict中的键名
返回值:
	Info属性的dict中的值
说明:
	jxTMS中经常使用json格式的Info字段来保存一些额外的数据,这主要是为了应对不断变化的小需求所需要的额外的数据保存点

setInfoValue(self,vn,v)

设置json格式的Info属性对应的dict中的vn名的值

参数:
	vn:Info属性的dict中的键名
	v:值
返回值:
	无

参考资料:

jxTMS设计思想

jxTMS编程手册

下面的系列文章讲述了如何用jxTMS开发一个实用的业务功能:

如何用jxTMS开发一个功能

下面的系列文章讲述了jxTMS的一些基本开发能力:

jxTMS的HelloWorld

你可能感兴趣的:(jxTMS,docker,python,jxTMS,SaaS)