使用Python的web.py框架實(shí)現(xiàn)類(lèi)似Django的ORM查詢(xún)的教程
Django中的對(duì)象查詢(xún)
Django框架自帶了ORM,實(shí)現(xiàn)了一些比較強(qiáng)大而且方便的查詢(xún)功能,這些功能和表無(wú)關(guān)。比如下面這個(gè)例子:
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中定義的,可能在其父類(lèi)models.Model中定義,也可能不是。那么我們?cè)趙eb.py中如何實(shí)現(xiàn)這樣的功能呢?(如果你選擇使用SQLAlchemy就不需要自己實(shí)現(xiàn)了)。
實(shí)現(xiàn)
思路
我們注意到Question.objects.all()這樣的調(diào)用是直接訪問(wèn)了類(lèi)屬性objects,并調(diào)用了objects屬性的方法all()。這里objects可能是一個(gè)實(shí)例,也可能是一個(gè)類(lèi)。我個(gè)人認(rèn)為(我沒(méi)看過(guò)Django的實(shí)現(xiàn))這應(yīng)該是一個(gè)實(shí)例,因?yàn)閷?shí)例化的過(guò)程可以傳遞一些表的信息,使得類(lèi)似all()這樣的函數(shù)可以工作。經(jīng)過(guò)分析之后,我們可以列出我們需要解決的問(wèn)題:
- 需要實(shí)現(xiàn)一個(gè)模型的父類(lèi)Model,實(shí)際的表可以從這個(gè)父類(lèi)繼承以獲得自己沒(méi)有定義的功能。
- 實(shí)際的模型類(lèi)(比如Question類(lèi))定義后,不實(shí)例話的情況下就要具備objects.all()這樣的查詢(xún)效果。
- 從上面的需求可以看出,我們需要在類(lèi)定義的時(shí)候就實(shí)現(xiàn)這些功能,而不是等到類(lèi)實(shí)例化的時(shí)候再實(shí)現(xiàn)這些功能。類(lèi)定義的時(shí)候?qū)崿F(xiàn)功能?這不就是metaclass(元類(lèi))做的事情嘛。因此實(shí)現(xiàn)過(guò)程大概是下面這樣的:
- 實(shí)現(xiàn)一個(gè)Model類(lèi),其綁定方法和表的增、刪、改有關(guān)。
- 修改Model類(lèi)的元類(lèi)為ModelMetaClass,該元類(lèi)定義的過(guò)程中為類(lèi)增加一個(gè)objects對(duì)象,該對(duì)象是一個(gè)ModelDefaultManager類(lèi)的實(shí)例,實(shí)現(xiàn)了表的查詢(xún)功能。
代碼
都說(shuō)不給代碼就是耍流氓,我還是給吧。說(shuō)明下:使用的數(shù)據(jù)庫(kù)操作都是web.py的db庫(kù)中的接口。
# -*- coding: utf-8 -*- import web import config # 自定義的配置類(lèi),可以忽略 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))
使用
首先定義表對(duì)應(yīng)的類(lèi):
class Users(Model): ...
使用就和Django的方式一樣:
>>> user_list = Users.objects.all()
- 利用Python的Django框架中的ORM建立查詢(xún)API
- Django ORM框架的定時(shí)任務(wù)如何使用詳解
- Django使用詳解:ORM 的反向查找(related_name)
- Django基于ORM操作數(shù)據(jù)庫(kù)的方法詳解
- 在Python的Django框架上部署ORM庫(kù)的教程
- Django中ORM表的創(chuàng)建和增刪改查方法示例
- django 常用orm操作詳解
- Django視圖之ORM數(shù)據(jù)庫(kù)查詢(xún)操作API的實(shí)例
- django_orm查詢(xún)性能優(yōu)化方法
- Django學(xué)習(xí)筆記之ORM基礎(chǔ)教程
- django框架使用orm實(shí)現(xiàn)批量更新數(shù)據(jù)的方法
相關(guān)文章
VSCode下配置python調(diào)試運(yùn)行環(huán)境的方法
這篇文章主要介紹了VSCode下配置python調(diào)試運(yùn)行環(huán)境的方法,需要的朋友可以參考下2018-04-04Python利用watchdog模塊監(jiān)控文件變化
這篇文章主要為大家介紹一個(gè)Python中的模塊:watchdog模塊,它可以實(shí)現(xiàn)監(jiān)控文件的變化。文中通過(guò)示例詳細(xì)介紹了watchdog模塊的使用,需要的可以參考一下2022-06-06python實(shí)現(xiàn)目錄樹(shù)生成示例
這篇文章主要介紹了python實(shí)現(xiàn)目錄樹(shù)生成示例,需要的朋友可以參考下2014-03-03pyqt4教程之實(shí)現(xiàn)windows窗口小示例分享
這篇文章主要介紹了pyqt4實(shí)現(xiàn)windows窗口小示例,需要的朋友可以參考下2014-03-03python實(shí)現(xiàn)自動(dòng)發(fā)送郵件發(fā)送多人、群發(fā)、多附件的示例
下面小編就為大家分享一篇python實(shí)現(xiàn)自動(dòng)發(fā)送郵件發(fā)送多人、群發(fā)、多附件的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01Python實(shí)現(xiàn)直方圖均衡基本原理解析
這篇文章主要介紹了Python實(shí)現(xiàn)直方圖均衡基本原理,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-08-08利用Django模版生成樹(shù)狀結(jié)構(gòu)實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于利用Django模版生成樹(shù)狀結(jié)構(gòu)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Django具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05