使用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 相关文章推荐
windows下python模拟鼠标点击和键盘输示例
Feb 28 Python
在Python的Django框架中获取单个对象数据的简单方法
Jul 17 Python
python使用matplotlib绘制折线图教程
Feb 08 Python
python实现分页效果
Oct 25 Python
python机器学习库常用汇总
Nov 15 Python
Python中常见的异常总结
Feb 20 Python
python如何为被装饰的函数保留元数据
Mar 21 Python
python实现知乎高颜值图片爬取
Aug 12 Python
使用Tensorflow实现可视化中间层和卷积层
Jan 24 Python
Python 防止死锁的方法
Jul 29 Python
Anaconda的安装与虚拟环境建立
Nov 18 Python
python Tkinter的简单入门教程
Apr 11 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
PHP检测用户是否关闭浏览器的方法
2016/02/14 PHP
PHP中文字符串截断无乱码解决方法
2016/10/10 PHP
PHP实现通过CURL上传文件功能示例
2018/05/30 PHP
解决Laravel无法使用COOKIE和SESSION的问题
2019/10/16 PHP
javaScript复制功能调用实现方案
2012/12/13 Javascript
jquery 卷帘效果实现代码(不同方向)
2013/02/05 Javascript
textarea 控制输入字符字节数(示例代码)
2013/12/27 Javascript
jQuery通过扩展实现抖动效果的方法
2015/03/11 Javascript
jQuery树形下拉菜单特效代码分享
2015/08/15 Javascript
jquery实现清新实用的网页菜单效果
2015/08/28 Javascript
全面解析Bootstrap表单使用方法(表单控件)
2015/11/24 Javascript
JS获取当前脚本文件的绝对路径
2016/03/02 Javascript
jQuery常见的选择器及用法介绍
2016/12/20 Javascript
详解javascript中var与ES6规范中let、const区别与用法
2020/01/11 Javascript
JavaScript交换变量常用4种方法解析
2020/09/02 Javascript
[20:21]《一刀刀一天》第十六期:TI国际邀请赛正式打响,总奖金超过550万
2014/05/23 DOTA
简要讲解Python编程中线程的创建与锁的使用
2016/02/28 Python
Python断言assert的用法代码解析
2018/02/03 Python
详解Django中六个常用的自定义装饰器
2018/07/04 Python
Python爬虫 scrapy框架爬取某招聘网存入mongodb解析
2019/07/31 Python
python下PyGame的下载与安装过程及遇到问题
2019/08/04 Python
python语言中有算法吗
2020/06/16 Python
css3实现垂直下拉动画菜单示例
2014/04/22 HTML / CSS
AmazeUI的JS表单验证框架实战示例分享
2020/08/21 HTML / CSS
英国安全产品购物网站:The Safe Shop
2017/03/20 全球购物
台湾乐天市场:日本No.1的网路购物网站
2017/03/22 全球购物
Roxy俄罗斯官方网站:冲浪和滑雪板的一切
2020/06/20 全球购物
叙述DBMS对数据控制功能有哪些
2016/06/12 面试题
EJB实例的生命周期
2016/10/28 面试题
巡警年度自我鉴定
2014/02/21 职场文书
2014教师专业技术工作总结
2014/12/03 职场文书
2014年安置帮教工作总结
2014/12/11 职场文书
政协委员个人总结
2015/03/03 职场文书
2015年文明创建工作总结
2015/04/30 职场文书
聘用合同范本
2015/09/21 职场文书
Tomcat starup.bat 脚本实现开机自启动
2022/04/20 Servers