前面ORM模块咱们已经完成了开发,接下来要作的就是对项目代码进行重构了。由于对底层数据库操做模块(db_helper.py)进行了改造,以前项目的接口代码全都跑不起来了。python
在写ORM模块时,咱们已经对产品接口的分页查询、新增、修改、获取指定产品实体接口已经重构好了,还剩下删除接口未完成web
1 @delete('/api/product/<id:int>/') 2 def callback(id): 3 """ 4 删除指定记录 5 """ 6 # 编辑记录 7 sql = """delete from product where id=%s returning id""" 8 vars = (id,) 9 # 写入数据库 10 result = db_helper.write(sql, vars) 11 # 判断是否提交成功 12 if result: 13 return web_helper.return_msg(0, '成功') 14 else: 15 return web_helper.return_msg(-1, "删除失败")
若是前面代码有认真学习的小伙伴看到这段代码,要改为ORM方式应该很容易实现了sql
只须要将第7行到第10行替换对应的调用代码就能够了数据库
1 @delete('/api/product/<id:int>/') 2 def callback(id): 3 """ 4 删除指定记录 5 """ 6 # 实例化product表操做类ProductLogic 7 _product_logic = product_logic.ProductLogic() 8 result = _product_logic.delete_model(id) 9 # 判断是否提交成功 10 if result: 11 return web_helper.return_msg(0, '成功') 12 else: 13 return web_helper.return_msg(-1, "删除失败")
首先是初始化产品逻辑层操做类,而后调用delete_model()这个方法就能够了json
当你习惯这种写法之后,你会发现实现各个接口会变得很是的简单与方便,开发速度比以前也提高了不少api
产品分类相关接口(product_class.py)与产品相关接口(product.py)功能差很少,具体实现我就不一一讲解了,你们能够本身试试缓存
产品分类的删除分类接口你们会看到它的代码与产品删除接口差很少,不过多了一个该分类是否已经被引用的一个判断,对于这个下面专门说明一下框架
1 @delete('/api/product_class/<id:int>/') 2 def callback(id): 3 """ 4 删除指定记录 5 """ 6 # 判断该分类是否已经被引用,是的话不能直接删除 7 sql = """select count(*) as total from product where product_class_id=%s""" % (id,) 8 # 读取记录 9 result = db_helper.read(sql) 10 if result and result[0].get('total', -1) > 0: 11 return web_helper.return_msg(-1, "该分类已被引用,请清除对该分类的绑定后再来删除") 12 13 # 编辑记录 14 sql = """delete from product_class where id=%s returning id""" 15 vars = (id,) 16 # 写入数据库 17 result = db_helper.write(sql, vars) 18 # 判断是否提交成功 19 if result: 20 return web_helper.return_msg(0, '成功') 21 else: 22 return web_helper.return_msg(-1, "删除失败")
这段代码后半部分能够参考产品的删除接口实现,前半部分须要调用产品方法进行判断处理。post
在编写时咱们会发现,咱们的ORM并无直接判断记录是否存在的方法,只有一个用于获取指定条件记录数的方法。学习
通常来讲,咱们在开发时发现ORM没有本身想要的方法时,咱们须要作如下思考:
1.有没有替代能够实现的方法存在
2.该功能是不是经常使用的功能,可否封装成公共方法,若是能够就将它封装到逻辑层基类(ORM模块)中去,让全部继承的子类都拥有这个功能
3.若是它只是对指定表单操做时才用到,就将它封装到该逻辑层子类,方便该子类要用到时能够随时调用
这段代码的要求是判断指定的分类是否被产品引用,抽象出来的意思就是判断指定条件的记录是否存在,对于这个功能有开发经验的小伙伴很容易判断它是不少地方都有可能要用到的通用方法,因此咱们须要在ORM中增长一下这个方法。而咱们ORM已经存在get_count()这个获取记录数的方法存在了,咱们能够经过调用这个方法来判断记录数量是否大于0,来得出指定条件的记录是否存在这样的结果。
def exists(self, wheres): """检查指定条件的记录是否存在""" return self.get_count(wheres) > 0
有了这个方法,咱们就能够继续对产品分类删除接口进行改造了
1 @delete('/api/product_class/<id:int>/') 2 def callback(id): 3 """ 4 删除指定记录 5 """ 6 # 实例化product表操做类ProductLogic 7 _product_logic = product_logic.ProductLogic() 8 # 判断该分类是否已经被引用,是的话不能直接删除 9 if _product_logic.exists('product_class_id=' + str(id)): 10 return web_helper.return_msg(-1, "该分类已被引用,请清除对该分类的绑定后再来删除") 11 12 # 实例化product_class表操做类product_class_logic 13 _product_class_logic = product_class_logic.ProductClassLogic() 14 result = _product_class_logic.delete_model(id) 15 # 判断是否提交成功 16 if result: 17 return web_helper.return_msg(0, '成功') 18 else: 19 return web_helper.return_msg(-1, "删除失败")
经过这个例子,你们在实际开发过程当中,能够灵活的根据本身须要,来增长或改造对应的底层方法,积累你本身的底层框架代码,那么随着开发时间的增长,你开发起各类功能来就会越加驾轻就熟了。
细心的朋友会发现,ORM模块的缓存部分,多了一个get_model_for_cache_of_where()方法,下面我来讲明一下它的用途。
咱们在开发时,除了经过主键id来获取记录实体之外,在有的数据表中,还会存在第二个主键,或多个主键的状况,咱们须要经过这些主键来获取对应的记录实休,好比说管理员或用户表中的登陆帐号字段;订单表中的订单编码字段等。
正常状况下,咱们直接经过get_model()方法就能够读取对应的记录了,若是咱们想减小数据库的查询,直接在缓存中如何使用呢?直接存取记录实体,因为这些额外的主键并无与ORM中的编辑与删除操做关联,即在进行编辑与删除操做时不会同步更新用其余主键存储的实体内容,这样就会产生脏数据。因此咱们能够换一种思路来实现,咱们能够将这些额外的主键和对应的值生成缓存组合key,里面存储对应的记录实体id,也就是说在存储记录实体时,仍是使用原来的主键id存储该实体,而后用额外主键和对应值生成缓存组合key中存储主键id,在获取记录实体时,先用这个组合key提取对应的id,再用这个id来获取记录实体。这个说明好像有点绕,你们本身debug一下就很容易明白其中的原理了,下面看代码:
1 def get_model_for_cache_of_where(self, where): 2 """ 3 经过条件获取记录实体————条件必须是额外的主键,也就是说记录是惟一的(咱们常常须要使用key、编码或指定条件来获取记录,这时能够经过当前方法来获取) 4 :param where: 查询条件 5 :return: 记录实体 6 """ 7 # 生成实体缓存key 8 model_cache_key = self.__table_name + encrypt_helper.md5(where) 9 # 经过条件从缓存中获取记录id 10 pk = cache_helper.get(model_cache_key) 11 # 若是主键id存在,则直接从缓存中读取记录 12 if pk: 13 return self.get_model_for_cache(pk) 14 15 # 不然从数据库中获取 16 result = self.get_model(where) 17 if result: 18 # 存储条件对应的主键id值到缓存中 19 cache_helper.set(model_cache_key, result.get(self.__pk_name)) 20 # 存储记录实体到缓存中 21 self.set_model_for_cache(result.get(self.__pk_name), result) 22 return result
下面改造调用例子(请查看login.py第35行附近)
1 ############################################################## 2 ### 获取登陆用户记录,并进行登陆验证 ### 3 ############################################################## 4 sql = """select * from manager where login_name='%s'""" % (username,) 5 # 从数据库中读取用户信息 6 manager_result = db_helper.read(sql) 7 # 判断用户记录是否存在 8 if not manager_result: 9 return web_helper.return_msg(-1, '帐户不存在')
咱们能够改造为:
1 ############################################################## 2 ### 获取登陆用户记录,并进行登陆验证 ### 3 ############################################################## 4 _manager_logic = manager_logic.ManagerLogic() 5 # 从数据库中读取用户信息 6 manager_result = _manager_logic.get_model_for_cache_of_where('login_name=' + string(username)) 7 # 判断用户记录是否存在 8 if not manager_result: 9 return web_helper.return_msg(-1, '帐户不存在')
还有登陆接口最底部,更新管理员最后登陆时、登陆ip和累加登陆次数须要改造,具体代码以下:
1 ############################################################## 2 ### 更新用户信息到数据库 ### 3 ############################################################## 4 # 更新当前管理员最后登陆时间、Ip与登陆次数(字段说明,请看数据字典) 5 sql = """update manager set last_login_time=%s, last_login_ip=%s, login_count=login_count+1 where id=%s""" 6 # 组合更新值 7 vars = ('now()', ip, manager_id,) 8 # 写入数据库 9 db_helper.write(sql, vars)
咱们能够更改成:
1 ############################################################## 2 ### 更新用户信息到数据库 ### 3 ############################################################## 4 # 更新当前管理员最后登陆时间、Ip与登陆次数(字段说明,请看数据字典) 5 fields = { 6 'last_login_time': 'now()', 7 'last_login_ip': string(ip), 8 'login_count': 'login_count+1', 9 } 10 # 写入数据库 11 _manager_logic.edit_model(manager_id, fields)
对于字段值,若是为字符串、具体时间、json等类型的,也就是说须要用单撇号括起来的,咱们就须要调用string_helper模块的string方法进行转换,它能够为变量增长单撇号,若是直接赋字符串值,生成的sql语句是没有单撇号的,这里要注意一下
若是是数值类型,直接写值就能够了,固然直接赋字符串值也没有关系,由于生成sql是不会自动添加单撇号的
若是要赋postgresql系统变量,如now(),直接像上面这样写就能够了
若是字段是数值型,要让它进行计算,直接像上面这样写也行,能够是多个字段用加号连起来。固然你也能够将字段时读出来进行计算后再赋值提交也没有问题
具体操做须要你们本身多debug,多测试使用才知道怎么应用到真实项目中。
版权声明:本文原创发表于 博客园,做者为 AllEmpty 本文欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然视为侵权。
python开发QQ群:669058475(本群已满)、733466321(能够加2群) 做者博客:http://www.cnblogs.com/EmptyFS/