内容简介:Django项目,一般是按照 APP 切分的,并且每一个 APP 有相似的结构,大家都是『各自管好自己份内的事情』,颇有点像微服务的味道。但是许多人写Django 的代码,没有一定的章法,一千个人一千种风格。甚至于,在Controller层出现直接裸调用如何组织、设计我们的这个层呢?我们没有必要自己绞尽脑汁闭门造车,可以参考成熟项目的做法。Java Spring 是我参考的对象,一般的Spring 项目,有着很明确分层结构,虽然初期需要写较多的代码,但是给后期的代码维护,着实带来了很多便利。一般会分为如下
Django项目,一般是按照 APP 切分的,并且每一个 APP 有相似的结构,大家都是『各自管好自己份内的事情』,颇有点像微服务的味道。但是许多人写Django 的代码,没有一定的章法,一千个人一千种风格。甚至于,在Controller层出现直接裸调用 UserModel.objects.filter
的情况也不少见。然而,我们发现,针对数据库的操作,很多都是通用的,这时候,单独抽取出一层,就显得很有必要了。
参考的对象
如何组织、设计我们的这个层呢?我们没有必要自己绞尽脑汁闭门造车,可以参考成熟项目的做法。Java Spring 是我参考的对象,一般的Spring 项目,有着很明确分层结构,虽然初期需要写较多的代码,但是给后期的代码维护,着实带来了很多便利。
一般会分为如下层级:
Controller Service Repository( DAO ) (Mapper,可选,如果使用了Mybatis的话) Model 复制代码
结合Django的特性,我们发现Django的Manager层(即: XXModel.objects
),其实是对应着 DAO 层的,只不过大家的叫法不同。
我们不妨将抽取的单独层,叫做DAO 好了,后面我们也会看到,它其实就是对 Manager 层的API进行组合,对上提供一些通用的操作。
如何写
在正式写之前,我们可以先根据实际经验,思考:应该提供哪些通用的API?下面是我根据自己的经验,得出的结论:
- save(obj)
- delete(obj)
- update(obj)
- findOne/findAll
那么通过什么手段实现呢?得益于 Python 强大的语言特性,让我们的代码可以不必写得像 Java 那样冗长乏味。我的步骤如下:
BaseDAO
下面是代码片段:
# 基于 Python 3.5 的代码, 如果想要放到 Python 2 中的同学, 可以去掉 Type Hint from .BaseModel import BaseModel # 一般的项目, 都会封装一个基类Model class BaseDAO: # 子类必须覆盖这个 MODEL_CLASS = BaseModel SAVE_BATCH_SIZE = 1000 def save(self, obj): """insert one :param obj: :return: """ if not obj: return False obj.save() return True def save_batch(self, objs, *, batch_size=SAVE_BATCH_SIZE): """insert batch :type objs: list[BaseModel] :param objs: :return: """ if not objs: return False self.MODEL_CLASS.objects.bulk_create(objs, batch_size=batch_size) return True def delete(self, obj): if not obj: return False obj.delete() return True def delete_batch(self, objs): if not objs: return False for obj in objs: self.delete(obj) return True def delete_batch_by_query(self, filter_kw: dict, exclude_kw: dict): """批量删除 """ self.MODEL_CLASS.objects.filter(**filter_kw).exclude(**exclude_kw).delete() return True def delete_by_fake(self, obj): """假删除/伪删除 """ if obj is None: return False obj.is_deleted = True obj.save() return True def update(self, obj): if not obj: return False obj.save() return True def update_batch(self, objs): if not objs: return False for obj in objs: self.update(obj) return True def update_batch_by_query(self, query_kwargs: dict, exclude_kw: dict, newattrs_kwargs: dict): self.MODEL_CLASS.objects.filter(**query_kwargs).exclude(**exclude_kw).update(**newattrs_kwargs) def find_one(self, filter_kw: dict, exclude_kw: dict, order_bys: list): """ :param query_kwargs: :rtype: BaseModel | None :return: """ qs = self.MODEL_CLASS.objects.filter(**filter_kw).exclude(**exclude_kw) if order_bys: qs = qs.order_by(*order_bys) return qs.first() def find_queryset(self, filter_kw: dict, exclude_kw: dict, order_bys: list): """ :param filter_kw: :return: """ return self.MODEL_CLASS.objects.filter(**filter_kw).exclude(**exclude_kw) def find_all_model_objs(self, filter_kw: dict, exclude_kw: dict, order_bys: list) -> list: return self.find_queryset(filter_kw, exclude_kw, order_bys).all() def is_exists(self, filter_kw:dict, exclude_kw:dict) -> bool: return self.MODEL_CLASS.objects.filter(**filter_kw).exclude(**exclude_kw).exists() def get_count(self, filter_kw:dict, exclude_kw:dict) -> int: return self.MODEL_CLASS.objects.filter(**filter_kw).exclude(**exclude_kw).count() 复制代码
如何使用
比如在某个 Django APP 中使用:
某个Django APP, 这里是 goods goods/ views.py tests.py dao/ ( 也可以单独放到一个 dao.py 中, 看自己喜好. 我比较喜欢弄一个目录, 并且每一个py 文件一个class, 这里保持和java一样的风格) GoodsDao.py models.py GoodsDao.py内容 from ..models import Goods from common_base import BaseDAO class GoodsDao(BaseDAO): MODEL_CLASS = Goods 复制代码
上层使用:基本可以很自由的使用。都是一些通用的CURD 操作,变化不大,并且再也不用写冗长的 XXModel.objects.filter
了
延伸
通过上面总结,我们可以看到,确实带来了一个良好的封装,虽然初期需要多写一些代码,但是后期代码维护比较舒服。另外一个问题是:是不是就该摒弃 Goods.objects.filter
这种写法呢?
我觉得不是的, Goods.objects.filter
仍然可以自由使用,只不过在 DAO 无法应对的情况下(你又懒得再封装了,因为是低频操作),就该轮到它出场了。它们两者应该是互为补充,互相融合,各自都有自己的使用场景。原始的写法适用于『比较低频、临时的CURD操作』,DAO则适用于『比较高频、通用的CURD操作』。
另外,Python 世界流行的 ORM ,不只有 Django ORM,SQLAlchemy等,你也可以封装出同样类似的 DAO 层,让自己的代码越写越舒服。
以上所述就是小编给大家介绍的《为你的Django APP 写一层 DAO》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数字时代的营销战略
曹虎、王赛、乔林、【美】艾拉·考夫曼 / 机械工业出版社 / 2017-1 / 99.00元
菲利普•科特勒说,市场比市场营销变得更快(Market changes faster than Marketing),在这个变革的时代,从硅谷、波士顿到北京、上海、深圳,我们正在重新定义公司,重新定义组织,重新定义战略;同样地,营销亦需要重新定义。 从本质上讲,营销战略只有两个时代:实体时代与比特时代,也可称为工业时代与数字时代。从5年前开始,第二个时代正在向未来20年展开画卷,数字创新型企......一起来看看 《数字时代的营销战略》 这本书的介绍吧!