我的第一个python web开发框架(27)——定制ORM(三)

  在上一章中,我们已经创建好ORM的基类了,接下来要做的就是将基类的常用方法一一实现。

  首先我们来看看之前项目中,最常见的获取指定主键的记录实体

@get('/api/product/<id:int>/')
def callback(id):
    """
    获取指定id的产品记录实体
    """
    sql = """select * from product where id = %s""" % (id,)
    # 读取记录
    result = db_helper.read(sql)
    if result:
        return web_helper.return_msg(0, '成功', result[0])
    else:
        return web_helper.return_msg(-1, "查询失败")

  从代码中可以看到,我们需要执行select * from product where id = xx从数据表中查询到我们想要的数据。

  要封装成ORM的方法,我需要需要注意下面几项事情:

  1.方法名必须是简单易懂的

  2.方法需要接收指定的主键值

  3.sql需要在方法中进行组装

  根据这些要求,我们可以很容易写出这个方法

    def get_model_for_pk(self, pk):
        """通过主键值获取数据库记录实体"""
        if not pk:
            return {}
        # 组装查询条件
        wheres = '%s = %s' % (self.__pk_name, str(pk))
        # 合成sql语句
        sql = "select %(column_name_list)s from %(table_name)s where %(wheres)s" % \
              {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
        # 初化化数据库链接
        with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
            # 执行sql语句
            _result = db.execute(sql)
            # 对返回的内容进行处理
            if _result:
                result = _result[0]
            else:
                result = {}
        return result

  我们通过方法名(get_model_for_pk)应当可以知道,我们是通过主键来获取指定的记录实体内容。

  该方法需要传入的参数值是主键值pk

  在接收到主健值以后,我们需要对它进行简单的判断处理,如果它为空则直接返回空字典。

  在组合sql前,我们需要选对查询条件进行组装,这里我们直接使用self.__pk_name,在上一章初始化时定义好的默认项,在这里不直接使用id做为条件字段,是为了当出现主键名称为其他字符时,可以灵活处理。比如订单表使用code为主键时,就可以直接绑定code而不是自增id了。比如self.__pk_name初始值是id,主键pk值是1,那么组装后的查询条件为 id=1

  然后直接调用默认项查询字段名称self.__column_name_list和表名称self.__table_name来合成sql语句。例如self.__column_name_list初始值为*,self.__table_name初始值为product,那么合成的sql语句为:select * from product where id=1

  最后调用数据库操作类db_helper来执行sql语句(这里使用widh方法来初始化数据库操作类),将执行后的结果返回主程序

 

  针对上面这个读取产品记录实体的功能,我们像上一章一样,先创建好一个产品管理的逻辑类,继承ORM基类

#!/usr/bin/env python
# coding=utf-8

from logic import _logic_base
from config import db_config


class ProductLogic(_logic_base.LogicBase):
    """产品管理表逻辑类"""

    def __init__(self):
        # 表名称
        __table_name = 'product'
        # 初始化
        _logic_base.LogicBase.__init__(self, db_config.DB, db_config.IS_OUTPUT_SQL, __table_name)

  我们就可以直接改造前面的接口调用代码了

@get('/api/product/<id:int>/')
def callback(id):
    """
    获取指定记录
    """
    # 实例化product表操作类ProductLogic
    _product_logic = product_logic.ProductLogic()
    # 执行get_model_for_pk()方法,获取记录实体
    model = _product_logic.get_model_for_pk(id)
    if model:
        return web_helper.return_msg(0, '查询成功', model)
    else:
        return web_helper.return_msg(-1, "查询失败")

  和前面的代码比较,代码看起来简单多了

  直接上单元测试看看执行效果

 1 #!/usr/bin/evn python
 2 # coding=utf-8
 3 
 4 import unittest
 5 from logic import product_logic
 6 
 7 class DbHelperTest(unittest.TestCase):
 8     """数据库操作包测试类"""
 9 
10     def setUp(self):
11         """初始化测试环境"""
12         print('------ini------')
13 
14     def tearDown(self):
15         """清理测试环境"""
16         print('------clear------')
17 
18     def test(self):
19         ##############################################
20         # 只需要看这里,其他代码是测试用例的模板代码 #
21         ##############################################
22         # 实例化product表操作类ProductLogic
23         _product_logic = product_logic.ProductLogic()
24         # 执行get_model_for_pk()方法,获取记录实体
25         model = _product_logic.get_model_for_pk(2)
26         print(model)
27 
28         ##############################################
29 
30 if __name__ == '__main__':
31     unittest.main()

  输出结果:

------ini------
{'product_class_id': 1, 'place_of_origin': '广东广州', 'name': '饼干', 'id': 2, 'standard': '500g', 'is_enable': 1, 'add_time': datetime.datetime(2018, 7, 25, 23, 10, 4), 'quality_guarantee_period': '2018年12月', 'code': '20180212321211', 'content': '产品描述', 'front_cover_img': 'http://xxx.com/xxx.jpg'}
------clear------

 

  做到这一步,一个简单的通过主键值读取数据表记录实体的ORM方法就完成了。

  为了让这个读取记录实体的功能能应用的更加广泛,我们还需要对它进行改造与加工。

  在开始之前,大家再继续思考一下,我们获取记录实体,通过主键查询只是众多方法中的其中一个,我们还会经常使用各种条件的组合来进行查询,读取记录实体,所以这里我们可以实现自定义条件查询的方法

    def get_model(self, wheres):
        """通过条件获取一条记录"""
        # 如果有条件,则自动添加where
        if wheres:
            wheres = ' where ' + wheres

        # 合成sql语句
        sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % \
              {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
        # 初化化数据库链接
        with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
            # 执行sql语句
            _result = db.execute(sql)
            # 对返回的内容进行处理
            if _result:
                result = _result[0]
            else:
                result = {}
        return result

  代码看起来与前面的get_model_for_pk()方法差不多,只不过将pk参数改为条件参数wheres,不需要再组合主键查询条件而已。由于两个函数部分代码一样,所以我们需要对get_model_for_pk()方法进行重构,直接将组装好的查询条件提交给get_model()方法来执行就可以了,将它返回的内容直接返回给主程序。

    def get_model_for_pk(self, pk, wheres=''):
        """通过主键值获取数据库记录实体"""
        if not pk:
            return {}
        # 组装查询条件
        wheres = '%s = %s' % (self.__pk_name, str(pk))

        return self.get_model(wheres)

  改造完成后,使用前面的单元测试跑一下,可以看到返回结果一样。增加了get_model()方法以后,我们就可以灵活的自定义任意的查询条件来读取记录了。这里要注意的是,使用get_model()方法查询时,有可能在查询时会返回多条记录,这个方法它只返回第一条记录。需要返回多条记录时,可以使用我们后续封装的其他ORM方法。

 

  

  本文对应的源码下载 (为了方便大家理解,源码包只放了这两章所用到的一些代码)

 

 

版权声明:本文原创发表于 博客园,作者为 AllEmpty 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。

python开发QQ群:669058475(本群已满)、733466321(可以加2群)    作者博客:http://www.cnblogs.com/EmptyFS/

 

 

posted @ 2018-08-03 00:15  AllEmpty  阅读(1925)  评论(1编辑  收藏  举报