xiaolingzi's blog

每天都在成长...

欢迎您:亲

Python ORM框架lingorm介绍及使用文档

xiaolingzi 发表于 2017-03-28 14:04:57

lingorm是使用python3编写的ORM框架,支持插入修改删除等基本ORM功能,也支持一般复杂的查询(比如复杂条件下的联表查询)。除此,也支持原生sql查询以应对更加复杂的情况。


一、框架的引入

下载代码,切换到代码根目录,运行 python setup.py install 即可进行安装。

GitHub地址:https://github.com/xiaolingzi/python-orm-lingorm


二、数据库配置

数据库采用json格式进行配置,内容格式如下:

{
    "testdb1":{
        "host":"192.168.0.22",
        "user":"db_user",
        "password":"password",
        "database":"dbname1",
        "charset":"utf8",
        "driver":"pdo_mysql"
    },
    "testdb2":{
        "host":"192.168.0.22",
        "user":"db_user",
        "password":"password",
        "database":"dbname2",
        "charset":"utf8",
        "driver":"pdo_mysql"
    },
    "testdb3":{
        "driver":"pdo_mysql",
        "database":"dbname3",
        "charset":"utf8",
        "user":"db_user",
        "password":"password",
        "servers":[
        {
            "host":"192.168.0.110",
            "mode":"w",
            "w_weight":3
        },
        {
            "host":"192.168.0.111",
            "mode":"rw",
            "w_weight":1,
            "weight":1
        },
        {
            "host":"192.168.0.112",
            "mode":"r",
            "weight":3
        },
        {
            "host":"192.168.0.113",
            "user":"db_user",
            "password":"password",
            "database":"dbname113",
            "charset":"utf8",
            "mode":"r",
            "weight":2
        }]
    }
}

1. 单台数据库服务器

单台的配置如testdb1和testdb2那样

2. 集群

一读多写、多读多写的情况配置如testdb3那样,将host属性改为servers属性,servers里面配置每个数据库信息:

1)读写配置通过mode属性,r为只读,w为只写,rw为读写

2)数据库名称、用户密码、编码等配置可以继承父节点配置,也可以自定义

3)多台配置通过权重随机的算法来决定连接那台服务器,读权重属性为weight、写权重的属性为w_weight

3.配置文件路径

然后修改Python\Lib\site-packages\lingorm-1.0.0-py3.5.egg\lingorm目录的config.py文件,设置数据库配置文件的路径(为了防止下次安装时又覆盖,这两个值可以在项目中直接给该类的属性进行赋值的方式进行修改)。文件内容如下:

import sys
                    
                    
class Config:
    default_database_server = "test"
    database_config_file = sys.path[0] + "/config/dev/database_config.json"

(1) 修改default_database_server的值,设置默认使用的数据库连接

(2) 修改database_config_file的值,设置实际数据库配置文件路径


三、实体类

1.实例及说明如下:

from lingorm.mapping import *
                    
                    
class TestEntity(ORMEntity):
    __table__ = "test"
    __database__ = "test"
    testId = Field(field_name="testId", field_type="int", primary_key=True, is_generated=True)
    testName = Field(field_name="testName", field_type="string")
    testTime = Field(field_type="datetime")
                    
    def __init__(self, **kwargs):
        self.testId = kwargs.get("testId")
        self.testName = kwargs.get("testName")
        self.testTime = kwargs.get("testTime")

实体类包含了类和表、属性和表字段之间的映射关系,参数如下:

(1) __table__ 表示该实体类对应的表名。必填

(2) __database__ 表示表所在数据库。可选,如没有该参数,则使用查询是提供的配置或者默认配置中的数据库作为该表的数据库。

Field参数如下:

(1) field_name 表示该属性对应的表字段。可选,如没有该参数则默认以该属性名作为字段名。

(2) field_type 字段类型。可选,默认为string。参数值主要有int,string,float,datetime。

(3) is_generated 字段值是否数据库自动生成。可选,默认为False。如果该值设置为True在插入的时候就不会使用该字段。

(4) primary_key 是否主键。可选,默认为False.对实体进行删除更新时会使用这些字段作为条件。

(5) length 字段长度。可选,改参数只对string字段使用。


2. 实体类的生成

调用tools包下的MysqlEntityGenerator.py模块的方法可以将mysql的表生成对应的实体类,调用方法如下:

from lingorm.tools.mysql_entity_generator import *
                    
file_dir = sys.path[0] + "/entity_generated"
MysqlEntityGenerator("127.0.0.1", "user", "password").generate("testdb", "test", file_dir)

  (1) 构造函数的参数分别为数据库的 host,user name,password

  (2) generate方法的参数分别为 数据库名称、表名和存储路径。其中表名和路径可选,表名为空则生成整个数据库的所有表,路径为空则默认在当前目录的entity_generated目录下。


四、基本功能

在介绍基本功能之前先简单说一下入口类Query以及where条件和order条件的构建,因为接下来的功能会用到,大家在这里先有个概念,也不用太纠结于此。跟踪后面的示例一起看会更明白。

Query类:

from lingorm.orm import *
db_query = Query("testdb1")

db_query是orm包下Query.py模块中Query类的实例,他是所有功能的入口,该类的构造方法接收一个可选参数$key,就是上面数据库配置中的testdb1和testdb2,表示查询使用的数据库连接,如果该参数没有则采用Config文件DEFAULT_DATABASE_SERVER指定的默认连接。

where条件构建:

db_query = Query("testdb1")
where = db_query.create_where()
where.set_or(TestEntity.testId.le(4), TestEntity.testId.gt(6))

通过create_where方法构建一个where对象,where对象有set_or和set_or两个方法对应于sql语句中的or和and,方法支持不定量参数,多个参数条件会用or或者and拼接起来,只传一个参数则没有拼接。如上面的示例其实就等于

testId<=4 or testId>6

复杂条件可以通过嵌套完成,如下:

where->set_or(
        TestEntity.testId->lt(2),
        where->get_and(TestEntity.testId.gt(3),TestEntity.testTime.lt("2017-01-01 00:00:00"))
);

其中

(1)TestEntity是要查询的表对象,就是表对应的实体类。

(2)条件中属性的比较运算符有如下:

gt 大于。如例子中的 TestEntity.testId.gt(6)

ge 大于等于

lt 小于

le 小于等于

eq 等于

neq 不等于

like 模糊匹配

in_ 对应sql中的in,注意后面有一个下划杠,因为单独的in属于保留字

nin 对应sql中的not in

order条件构建:

db_query = Query("testdb1")
order = db_query.create_order()
order.order_by(TestEntity.testId, "asc").order_by(TestEntity.testName, "desc")

如上例,order by的条件构建就比较简单,通过create_order创建order对象,并调用它的order_by方法设置排序字段即可。

1.单条查询

db_query = Query("testdb1")
where = db_query.create_where()
where.set_and(TestEntity.testId.eq(4))
result = db_query.create_query().fetch_one(TestEntity, where)

其中fetch_one方法中的第三个参数order为可选。


2.多条查询

db_query = Query("testdb1")
where = db_query.create_where()
where.set_or(TestEntity.testId.le(4), TestEntity.testId.gt(6))
order = db_query.create_order()
order.order_by(TestEntity.testId, "asc").order_by(TestEntity.testName, "desc")
result = db_query.create_query().fetch_all(TestEntity, where, order)

fetch_all方法中的order参数也是可选。


3.单条插入

entity = TestEntity()
entity.testName = "python"
entity.testTime = datetime.datetime.now()
db_query = Query("testdb1")
result = db_query.create_query().insert(entity)

4.批量插入

entity_list = []
for i in range(1, 5):
    entity = TestEntity()
    entity.testName = "python" + str(i)
    entity.testTime = datetime.datetime.now()
    entity_list.append(entity)
    db_query = Query("testdb1")
result = db_query.create_query().batch_insert(entity_list)

5.单条更新

entity = fetch_one()
entity.testName = "edit name"
db_query = Query("testdb1")
result = db_query.create_query().update(entity)

6.批量更新

entity_list = fetch_all()
for entity in entity_list:
    entity.testName = "sample name"
    db_query = Query("testdb1")
result = db_query.create_query().batch_update(entity_list)

7.条件更新

set_list = [
    TestEntity.testName.eq("sample"),
    TestEntity.testTime.eq(datetime.datetime.now())
]
db_query = Query("testdb1")
where = db_query.create_where()
where.set_and(TestEntity.testId.le(4))
result = db_query.create_query().update_by(TestEntity, set_list, where)

8.单条删除

entity = TestEntity()
entity.testId = 6
db_query = Query("testdb1")
result = db_query.create_query().delete(entity)

9.条件删除

db_query = Query("testdb1")
where = db_query.create_where()
where.set_and(TestEntity.testId.le(9), TestEntity.testId.gt(7))
result = db_query.create_query().delete_by(TestEntity, where)

五、复杂查询

1.单表查询

复杂查询通过Query中的create_query_builder创建的查询构造器进行,如下例:

db_query = Query("testdb1")
where = db_query.create_where()
where.set_and(TestEntity.testId.le(4))
                    
query_builder = db_query.create_query_builder()
query_builder.select(TestEntity.testTime, TestEntity.testName.alias("testName2")) \
    .where(where) \
    .order_by(TestEntity.testId, "asc") \
    .limit(2)
result = query_builder.get_result()

这里需要注意的是,where的参数还是通过where构造器创建,而order by则直接调用order_by方法,多个排序字段调用多次即可。

select的字段支持count、sum、distinct和alias,如:

TestEntity.testId.count().alias("num")

转为sql为

count(testId) as num

由如

TestEntity.testId.distinct()

转为sql为

distinct testId

2.联表查询

看下面示例:

db_query = Query("testdb1")
where = db_query.create_where()
where.set_and(TestEntity.testId.le(4))
                    
on_condition = db_query.create_where()
on_condition.set_and(TestEntity.testId.eq(TestSecondEntity.testId))
                    
query_builder = db_query.create_query_builder()
query_builder.select(TestEntity.testTime, TestEntity.testName.alias("testName2"), TestSecondEntity) \
    .from_table(TestEntity) \
    .left_join(TestSecondEntity, on_condition) \
    .where(where) \
    .order_by(TestEntity.testId, "asc") \
    .limit(2)
result = query_builder.get_result()

分别支持 left_join, right_join 和 inner_join。on条件也是通过where条件构造器构造。

3.指定结果类

默认调用get_result方法返回的是一个list类型,每条结果为dict类型,如果想指定结果类,可以在该方法传入结果类的实例。如:

result = query_builder.get_result(TestEntity)

如此返回的结果将是TestEntity类对象列表,优先根据字段名和实体属性的映射关系将对应列的值赋予对应属性,没有的话会使用字段名作为对象的动态属性。

4.分页数据返回

将get_result改为get_page_result可以获取分页结果

result = query_builder.get_page_result(page_index, page_size, TestEntity)

返回结果为一个dict结果集,包含以下值:

total_count 总条数

total_pages 总页数

data 数据列表,如果不传结果类对象参数则每条数据均为dict类型,传则每条数据均为结果类对象。

五、原生sql查询

对于一些更复杂的查询,还可以通过原生sql语句进行查询,框架提供了两种类型的原型sql执行。

1.执行语句,返回影响数

sql = "update test set testName='first name' where testId=:testId"
param_dict = {"testId": 1}
db_query = Query("testdb1")
result = db_query.create_sql().execute(sql, param_dict)

所有查询通过都必须是参数化查询,而且严格为以上参数方式,如参数 :testId

2.执行语句,返回查询结果

sql = "select * from test where testId=:testId"
param_dict = {"testId": 1}
db_query = Query("love")
result = db_query.create_sql().get_result(sql, param_dict)

同样有get_result和get_page_result两个接口


以上就是所有说明,如有出错,请指正。


      

转载请注明出处:http://www.xxling.com/article/3108.aspx

  • 分类: Python
  • 阅读: (1243)
  • 评论: (0)
拍砖 取消
请输入昵称
请输入邮箱
*
 选择评论类型
300字以内  请输入评论内容