看了一下廖雪峰的那个web框架,其实就是封装了web.py,请求使用异步并将aiomysql做为MySQL数据库提供了异步IO的驱动,前端部分则整合了jinja.其中最难的应该是orm部分了。

下面是orm一个简单的例子。

class User(Model):
__table__ = 'users' id = StringField(primary_key=True, default=next_id, ddl='varchar(50)')
email = StringField(ddl='varchar(50)')
passwd = StringField(ddl='varchar(50)')
admin = BooleanField()
name = StringField(ddl='varchar(50)')
image = StringField(ddl='varchar(500)')
created_at = FloatField(default=time.time)

整体来看这是一个为User的简单table,集成了Model类。然后字段则是各种类型Field。

1.先来看看字段,也就是Field部分。Field部分比较简单,继承了object,然后初始化一些字段,其实没什么好说的。在字段赋值时,参数以dict格式传入,传入到哪里呢,本来type的dict是为none的,但下面这段代码用__new__改变了原来的type,而元类是创建类的类,因此,Field字段的参数,都会在ModelMetaclass类中做处理,下面看个调试的例子,看看元类的威力。

IPython 4.0.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details. In [1]: from orm import Model In [2]: class Blog(Model):
...: pass
...: In [3]: In [3]: a=Blog In [4]: type(a)
Out[4]: orm.ModelMetaclass In [5]: dir(a)
Out[5]:
['__class__',
'__contains__',
'__delattr__',
'__delitem__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__fields__',
'__format__',
'__ge__',
'__getattr__',
'__getattribute__',
'__getitem__',
'__gt__',
'__hash__',
'__init__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mappings__',
'__module__',
'__ne__',
'__new__',
'__primary_key__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__table__',
'__weakref__',
'clear',
'copy',
'find',
'findAll',
'findNumber',
'fromkeys',
'get',
'getValue',
'getValueOrDefault',
'items',
'keys',
'pop',
'popitem',
'remove',
'save',
'setdefault',
'update',
'values'] In [6]:

从上面可以看到,a是继承了元类修改后的类Blog的一个对象,因此继承了新增的属性跟方法。所以元类都能对所有的orm中的表做出约束和修改。

下面这段继承自type的ModelMetaclass就是元类的代码。

class ModelMetaclass(type):

    def __new__(cls, name, bases, attrs):
if name=='Model':
return type.__new__(cls, name, bases, attrs)
tableName = attrs.get('__table__', None) or name
logging.info('found model: %s (table: %s)' % (name, tableName))
mappings = dict()
fields = []
primaryKey = None
for k, v in attrs.items():
if isinstance(v, Field):
logging.info(' found mapping: %s ==> %s' % (k, v))
mappings[k] = v
if v.primary_key:
# 找到主键:
if primaryKey:
raise StandardError('Duplicate primary key for field: %s' % k)
primaryKey = k
else:
fields.append(k)
if not primaryKey:
raise StandardError('Primary key not found.')
for k in mappings.keys():
attrs.pop(k)
escaped_fields = list(map(lambda f: '`%s`' % f, fields))
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
attrs['__table__'] = tableName
attrs['__primary_key__'] = primaryKey # 主键属性名
attrs['__fields__'] = fields # 除主键外的属性名
attrs['__select__'] = 'select `%s`, %s from `%s`' % (primaryKey, ', '.join(escaped_fields), tableName)
attrs['__insert__'] = 'insert into `%s` (%s, `%s`) values (%s)' % (tableName, ', '.join(escaped_fields), primaryKey, create_args_string(len(escaped_fields) + 1))
attrs['__update__'] = 'update `%s` set %s where `%s`=?' % (tableName, ', '.join(map(lambda f: '`%s`=?' % (mappings.get(f).name or f), fields)), primaryKey)
attrs['__delete__'] = 'delete from `%s` where `%s`=?' % (tableName, primaryKey)
return type.__new__(cls, name, bases, attrs)

而Model类相对简单,主要是为了初始化了get/set以及几个getvalue的函数,这一块根据自己需要看看就好。

class Model(dict, metaclass=ModelMetaclass):

    def __init__(self, **kw):
super(Model, self).__init__(**kw) def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Model' object has no attribute '%s'" % key) def __setattr__(self, key, value):
self[key] = value def getValue(self, key):
return getattr(self, key, None) def getValueOrDefault(self, key):
value = getattr(self, key, None)
if value is None:
field = self.__mappings__[key]
if field.default is not None:
value = field.default() if callable(field.default) else field.default
logging.debug('using default value for %s: %s' % (key, str(value)))
setattr(self, key, value)
return value @classmethod
@asyncio.coroutine
def findNumber(cls, selectField, where=None, args=None):
' find number by select and where. '
sql = ['select %s _num_ from `%s`' % (selectField, cls.__table__)]
if where:
sql.append('where')
sql.append(where)
rs = yield from select(' '.join(sql), args, 1)
if len(rs) == 0:
return None
return rs[0]['_num_'] ....

@classmethod是为了将方法变成类方法,@asyncio.coroutine则是为了做异步处理。

那每一个orm下面的表是如何进行值传递的呢?下面看看另一个调试例子

In [2]: from orm import Model,StringField

In [3]: class Blog(Model):
...: __table__='user'
...: id=StringField(ddl='varchar(50)')
...: age=StringField(name="ss")
...: In [4]: a = Blog In [5]: dir(a)
Out[5]:
['__class__',
'__contains__',
'__delattr__',
'__delitem__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__fields__',
'__format__',
'__ge__',
'__getattr__',
'__getattribute__',
'__getitem__',
'__gt__',
'__hash__',
'__init__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mappings__',
'__module__',
'__ne__',
'__new__',
'__primary_key__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__table__',
'__weakref__',
'age',
'clear',
'copy',
'find',
'findAll',
'findNumber',
'fromkeys',
'get',
'getValue',
'getValueOrDefault',
'id',
'items',
'keys',
'pop',
'popitem',
'remove',
'save',
'setdefault',
'update',
'values'] In [6]: In [6]: a.__dict__
Out[6]: mappingproxy({'age': <orm.StringField object at 0x0000000004899A20>, '__
mappings__': {}, '__table__': 'user', '__primary_key__': None, '__module__': '__
main__', '__doc__': None, '__fields__': [], 'id': <orm.StringField object at 0x0
0000000048999E8>})
In [7]: a.__mappings__
Out[7]: {}

从这里可以看到,是以{'id':object,'age':object}向上传递到元类的attr,最后在__new__中处理后,重新传递给__init__初始化。

浅谈python web框架中的orm设计的更多相关文章

  1. 浅谈Python web框架

    一.Python web框架 Web Framework,Ruby的世界Rails一统江湖,而Python则是一个百花齐放的世界,各种micro-framework.framework不可胜数,不完全 ...

  2. 浅谈Python Web 框架:Django, Twisted, Tornado, Flask, Cyclone 和 Pyramid

    Django Django 是一个高级的 Python Web 框架,支持快速开发,简洁.实用的设计.如果你正在建一个和电子商务网站相似的应用,那你应该选择用 Django 框架.它能使你快速完成工作 ...

  3. [转]浅谈Python web框架

    说到web framework,Ruby的世界Rails一统江湖,而Python则是一个百花齐放的世界,各种micro-framework.framework不可胜数,不完全列表见:http://wi ...

  4. 浅谈python web框架django2.x

    1.Django简介 Python下有多款不同的 Web 框架,Django是最有代表性的一种.许多成功的网站和APP都基于Django. Django是一个开源的Web应用框架,由Python写成. ...

  5. 浅谈Python Web的五大框架

    说到Web Framework,Ruby的世界Rails一统江湖,而Python则是一个百花齐放的世界.各种micro-framework.framework不可胜数. 尽管还有一大脚本语言PHP也有 ...

  6. 浅谈网站web框架的本质

    一.web框架的本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. import socket def handle_reques ...

  7. 浅谈Python Django框架

    1.Django简介 Python下有多款不同的 Web 框架,Django是最有代表性的一种.许多成功的网站和APP都基于Django. Django是一个开源的Web应用框架,由Python写成. ...

  8. Python Web框架(URL/VIEWS/ORM)

    一.路由系统URL1.普通URL对应 url(r'^login/',views.login) 2.正则匹配 url(r'^index-(\d+).html',views.index) url(r'^i ...

  9. python三大web框架Django,Flask,Flask,Python几种主流框架,13个Python web框架比较,2018年Python web五大主流框架

    Python几种主流框架 从GitHub中整理出的15个最受欢迎的Python开源框架.这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等. Django: Python We ...

随机推荐

  1. iOS代码加密常用加密方式

    iOS代码加密常用加密方式 iOS代码加密常用加密方式,常见的iOS代码加密常用加密方式算法包括MD5加密.AES加密.BASE64加密,三大算法iOS代码加密是如何进行加密的,且看下文 MD5 iO ...

  2. C语言中的函数与指针

    1. 为什么需要函数? 函数就是功能的封装. 函数就是为了实现某个功能而编写的一段代码 scanf()    ,  printf() 2.函数优点: 代码更简洁 代码复用 如果业务逻辑变化,只把相应的 ...

  3. array_filter、array_map、array_walk解释

    /** * array_filter 用回调函数处理数组中的各个元素, * 重点在于过滤(而不是新增)某个元素,当你处理到一个元素时, * 如果返回了false,那么这个元素将会被过滤掉.PS:保持了 ...

  4. .NET项目工程生成一份项目帮助文档chm--Sandcastle工具

    Sandcastle的,由Microsoft创建的,是从创建MSDN风格的文档中使用的工具.NET程序集和关联的XML注释文件.目前的版本是 2010年6月发布.这是命令行并没有GUI前端,项目管理功 ...

  5. luemn PHP_CodeSniffer的安装

    1.PHP_CodeSniffer是PEAR中的一个用PHP5写的用来检查嗅探PHP代码是否有违反一组预先设置好的编码标准的一个包,它是确保你的代码简洁一致的必不可少的开发工具,甚至还可以帮助程序员减 ...

  6. Spring源码阅读:IOC容器的设计与实现(二)——ApplicationContext

    上一主题(查看)中,了解了IOC容器的基本概念,以及BeanFactory的设计与实现方式,这里就来了解一下ApplicationContext方式的实现. ApplicationContext 在S ...

  7. 最近用Timer踩了一个坑,分享一下避免别人继续踩

    最近做一个小项目,项目中有一个定时服务,需要向对方定时发送数据,时间间隔是1.5s,然后就想到了用C#的Timer类,我们知道Timer 确实非常好用,因为里面有非常人性化的start和stop功能, ...

  8. Parameter 'id' not found. Available parameters are [1, 0, param1, param2]异常

    出现此类异常可能的原因:Mapper.xml文件中的parameterType的类型与传入的参数类型不匹配

  9. 与POS机通信时的3DES(双倍长)加密解密

    项目中有个SocketServer要和移动便携POS机通信,POS开发商就告诉我们他们用的3DES(双倍长)加密,给了个Key.数据和结果,让我们实现. c#用TripleDESCryptoServi ...

  10. MySQL入门(一)

    最近一直都在搞新员工的培训材料,MySQL的培训PPT我居然写了100多页,我都佩服我自己的毅力了.不如现在把这些总结一下,慢慢写到博客里,供入门者参考. 一 关系型数据库 关系型数据库的理论提出于上 ...