使用Python的web.py框架实现类似Django的ORM查询的教程


Posted in Python onMay 02, 2015

Django中的对象查询

Django框架自带了ORM,实现了一些比较强大而且方便的查询功能,这些功能和表无关。比如下面这个例子:

class Question(models.Model):
  question_text = models.CharField(max_length=200)
  pub_date = models.DateTimeField('date published')


>>> Question.objects.all()
>>> Question.objects.get(pk=1)

从例子可以看出,objects.all和objects.get这些功能都不是在class Question中定义的,可能在其父类models.Model中定义,也可能不是。那么我们在web.py中如何实现这样的功能呢?(如果你选择使用SQLAlchemy就不需要自己实现了)。
实现
思路

我们注意到Question.objects.all()这样的调用是直接访问了类属性objects,并调用了objects属性的方法all()。这里objects可能是一个实例,也可能是一个类。我个人认为(我没看过Django的实现)这应该是一个实例,因为实例化的过程可以传递一些表的信息,使得类似all()这样的函数可以工作。经过分析之后,我们可以列出我们需要解决的问题:

  •     需要实现一个模型的父类Model,实际的表可以从这个父类继承以获得自己没有定义的功能。
  •     实际的模型类(比如Question类)定义后,不实例话的情况下就要具备objects.all()这样的查询效果。
  • 从上面的需求可以看出,我们需要在类定义的时候就实现这些功能,而不是等到类实例化的时候再实现这些功能。类定义的时候实现功能?这不就是metaclass(元类)做的事情嘛。因此实现过程大概是下面这样的:
  •     实现一个Model类,其绑定方法和表的增、删、改有关。
  •     修改Model类的元类为ModelMetaClass,该元类定义的过程中为类增加一个objects对象,该对象是一个ModelDefaultManager类的实例,实现了表的查询功能。

代码

都说不给代码就是耍流氓,我还是给吧。说明下:使用的数据库操作都是web.py的db库中的接口。

# -*- coding: utf-8 -*-

  import web

  import config # 自定义的配置类,可以忽略


  def _connect_to_db():
    return web.database(dbn="sqlite", db=config.dbname)


  def init_db():
    db = _connect_to_db()
    for statement in config.sql_statements:
      db.query(statement)


  class ModelError(Exception):
    """Exception raised by all models.

    Attributes:
      msg: Error message.
    """

    def __init__(self, msg=""):
      self.msg = msg

    def __str__(self):
      return "ModelError: %s" % self.msg


  class ModelDefaultManager(object):
    """ModelManager implements query functions against a model.

    Attributes:
      cls: The class to be managed.
    """

    def __init__(self, cls):
      self.cls = cls
      self._table_name = cls.__name__.lower()

    def all(self):
      db = _connect_to_db()
      results = db.select(self._table_name)
      return [self.cls(x) for x in results]

    def get(self, query_vars, where):
      results = self.filter(query_vars, where, limit=1)
      if len(results) > 0:
        return results[0]
      else:
        return None

    def filter(self, query_vars, where, limit=None):
      db = _connect_to_db()
      try:
        results = db.select(self._table_name, vars=query_vars, where=where,
                  limit=limit)
      except (Exception) as e:
        raise ModelError(str(e))

      return [self.cls(x) for x in results]


  class ModelMetaClass(type):

    def __new__(cls, classname, bases, attrs):
      new_class = super(ModelMetaClass, cls).__new__(cls, classname,
                              bases, attrs)
      objects = ModelDefaultManager(new_class)
      setattr(new_class, "objects", objects)

      return new_class


  class Model(object):
    """Parent class of all models.
    """

    __metaclass__ = ModelMetaClass

    def __init__(self):
      pass

    def _table_name(self):
      return self.__class__.__name__.lower()

    def insert(self, **kargs):
      db = _connect_to_db()
      try:
        with db.transaction():
          db.insert(self._table_name(), **kargs)
      except (Exception) as e:
        raise ModelError(str(e))

    def delete(self, where, using=None, vars=None):
      db = _connect_to_db()
      try:
        with db.transaction():
          db.delete(self._table_name(), where, vars=vars)
      except (Exception) as e:
        raise ModelError(str(e))

    def save(self, where, vars=None, **kargs):
      db = _connect_to_db()
      try:
        with db.transaction():
          db.update(self._table_name(), where, vars, **kargs)
      except (Exception) as e:
        raise ModelError(str(e))

使用

首先定义表对应的类:

class Users(Model):
  ...

使用就和Django的方式一样:

>>> user_list = Users.objects.all()

 

Python 相关文章推荐
python解析xml模块封装代码
Feb 07 Python
Python查找相似单词的方法
Mar 05 Python
Python实现的批量下载RFC文档
Mar 10 Python
python中的代码编码格式转换问题
Jun 10 Python
python list是否包含另一个list所有元素的实例
May 04 Python
利用Python读取txt文档的方法讲解
Jun 23 Python
在pytorch中查看可训练参数的例子
Aug 18 Python
python 生成器和迭代器的原理解析
Oct 12 Python
Pytorch: 自定义网络层实例
Jan 07 Python
django rest framework serializers序列化实例
May 13 Python
python 贪心算法的实现
Sep 18 Python
Docker如何部署Python项目的实现详解
Oct 26 Python
在ironpython中利用装饰器执行SQL操作的例子
May 02 #Python
用Python编写简单的定时器的方法
May 02 #Python
用Python程序抓取网页的HTML信息的一个小实例
May 02 #Python
在Mac OS上部署Nginx和FastCGI以及Flask框架的教程
May 02 #Python
在Python的Django框架中用流响应生成CSV文件的教程
May 02 #Python
详细解读Python中的__init__()方法
May 02 #Python
举例讲解Python的Tornado框架实现数据可视化的教程
May 02 #Python
You might like
header导出Excel应用示例
2014/01/24 PHP
PHP读取XML格式文件的方法总结
2017/02/27 PHP
jQuery 处理网页内容的实现代码
2010/02/15 Javascript
jQuery制作仿腾讯web qq用户体验桌面
2013/08/20 Javascript
httpclient模拟登陆具体实现(使用js设置cookie)
2013/12/11 Javascript
node.js实现博客小爬虫的实例代码
2016/10/08 Javascript
js 转json格式的字符串为对象或数组(前后台)的方法
2016/11/02 Javascript
AngularJS过滤器filter用法分析
2016/12/11 Javascript
Swiper自定义分页器使用详解
2017/12/28 Javascript
node实现爬虫的几种简易方式
2019/08/22 Javascript
node 标准输入流和输出流代码实例
2019/09/19 Javascript
JS实现吸顶特效
2020/01/08 Javascript
js 使用ajax设置和获取自定义header信息的方法小结
2020/03/12 Javascript
Vue2.0 ES6语法降级ES5的操作
2020/10/30 Javascript
ES6的循环与可迭代对象示例详解
2021/01/31 Javascript
[03:46]显微镜下的DOTA2第七期——满血与残血
2014/06/20 DOTA
利用python批量检查网站的可用性
2016/09/09 Python
详解django自定义中间件处理
2018/11/21 Python
django 做 migrate 时 表已存在的处理方法
2019/08/31 Python
Python3实现二叉树的最大深度
2019/09/30 Python
基于Python检测动态物体颜色过程解析
2019/12/04 Python
python已协程方式处理任务实现过程
2019/12/27 Python
解决Keras 与 Tensorflow 版本之间的兼容性问题
2020/02/07 Python
PyCharm取消波浪线、下划线和中划线的实现
2020/03/03 Python
Python如何实现后端自定义认证并实现多条件登陆
2020/06/22 Python
利用Python实现斐波那契数列的方法实例
2020/07/26 Python
RentCars.com巴西:汽车租赁网站
2016/08/22 全球购物
天猫超市:阿里巴巴打造的网上超市
2016/11/02 全球购物
Rodd & Gunn澳大利亚官网:新西兰男装品牌
2018/09/25 全球购物
护士实习鉴定范文
2013/12/22 职场文书
六一儿童节活动总结
2014/08/27 职场文书
设立有限责任公司出资协议书
2014/11/01 职场文书
幼儿园托班教育随笔
2015/08/14 职场文书
优质护理服务心得体会
2016/01/22 职场文书
PHP连接MSSQL数据库案例,PHPWAMP多个PHP版本连接SQL Server数据库
2021/04/16 PHP
SpringBoot整合Minio文件存储
2022/04/03 Java/Android