首页 > 编程语言 >python编程(orm原理和实践)

python编程(orm原理和实践)

时间:2022-11-23 13:01:21浏览次数:66  
标签:__ .__ name python self 编程 orm attrs def

就给出自己对orm的理解。之前廖雪峰给出的code,大家可以通过​​地址​​下载的到。

1、orm的使用方法

    一般我们使用orm都是这么写代码的,

class User(Model):
id = IntegerField('uid')
name = StringField('username')
email = StringField('email')
password = StringField('password')

u = User(id=12345, name='Michael', email='[email protected]', password='my-pwd')
u.save()

    这其中,User定义了数据类型,创建的时候直接用User实例化就可以了。这里的save表明了我们希望对User进行的操作,实际调用的时候包括了create、search、update和delete这些操作。

2、从save函数触发

    从代码中可以看出,User本身没有定义save函数,那么它只有从父类中继承而来,我们看看save函数在不在Model类中。下面来分析一下Model类,

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 save(self):
fields = []
params = []
args = []
for k, v in self.__mappings__.iteritems():
fields.append(v.name)
params.append('?')
args.append(getattr(self, k, None))

sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
print('SQL: %s' % sql)
print('ARGS: %s' % str(args))

    Model类果然没有令我们失望,save函数就在里面。从代码内容,我们大体看到不管是fileds、params,还是args都是根据__mapping__数据来获取到的。那么奇怪了,__mapping__又是哪里来的?这个时候__metaclass__就派上用场了。

3、自定义__metaclass__

    根据python的定义,如果类中出现了自定义__metaclass__,那么编译器会默认调用对应class下的__new__函数。这个时候,对我们来说,就需要看看ModelMetaclass里面做了些什么,

class ModelMetaclass(type):

def __new__(self, name, bases, attrs):
if name=='Model':
return type.__new__(self, name, bases, attrs)

print('Found model: %s' % name)
mappings = dict()
for k, v in attrs.iteritems():
if isinstance(v, Field):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v
for k in mappings.iterkeys():
attrs.pop(k)
attrs['__mappings__'] = mappings
attrs['__table__'] = name
return type.__new__(self, name, bases, attrs)

    从ModelMetaclass这个唯一的__new__函数来看,所有的变量都被函数进行了处理。首先,函数判断name是否为Model,是则不做处理,反之进行改写。其次,函数定义了mappings这个变量,它搜集了attrs中的Field变量,并且将这些变量从attrs踢出去。最后函数将修改后的attrs保存,重新进行type处理。

4、关于数据类型定义

    数据类型的定义比较简单。基本上就是按照父类加子类的办法进行的。唯一需要记住的,就是User类中的变量是类变量,不是实例变量,这一点要考虑清楚。

class Field(object):
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '<%s:%s>' % (self.__class__.__name__, self.name)

class StringField(Field):
def __init__(self, name):
super(StringField, self).__init__(name, 'varchar(100)')

class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'bigint')

5、完整代码

    最后给出完整代码,大家可以直接copy上面的地址下载。这里也给出一份,大家可以直接拿来进行调试练习。代码版权归原作者廖雪峰,请大家保留原作者的文件签名。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

' Simple ORM using metaclass '

__author__ = 'Michael Liao'

class Field(object):
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '<%s:%s>' % (self.__class__.__name__, self.name)

class StringField(Field):
def __init__(self, name):
super(StringField, self).__init__(name, 'varchar(100)')

class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'bigint')

class ModelMetaclass(type):

def __new__(self, name, bases, attrs):
if name=='Model':
return type.__new__(self, name, bases, attrs)

print('Found model: %s' % name)
mappings = dict()
for k, v in attrs.iteritems():
if isinstance(v, Field):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v
for k in mappings.iterkeys():
attrs.pop(k)
attrs['__mappings__'] = mappings
attrs['__table__'] = name
return type.__new__(self, name, bases, attrs)

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 save(self):
fields = []
params = []
args = []
for k, v in self.__mappings__.iteritems():
fields.append(v.name)
params.append('?')
args.append(getattr(self, k, None))

sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
print('SQL: %s' % sql)
print('ARGS: %s' % str(args))

# testing code:
class User(Model):
id = IntegerField('uid')
name = StringField('username')
email = StringField('email')
password = StringField('password')

u = User(id=12345, name='Michael', email='[email protected]', password='my-pwd')
u.save()


标签:__,.__,name,python,self,编程,orm,attrs,def
From: https://blog.51cto.com/feixiaoxing/5881017

相关文章

  • python编程(gevent入门)
        大家都知道python脚本执行的时候不是很快,特别是python下面的多线程机制,长久以来一直被大家所诟病。所以,很多同学都在思考python下面有没有什么方法可以让python执行......
  • python编程(巧用装饰器)
        以前没有用过装饰器,也不知道它有什么用。直到最近写了一个log函数,在直到原来python的装饰器可以这么方便。1、原来debug消息的写法    假设有一个process函数,......
  • python编程(类变量和实例变量)
        关于类变量和实例变量,一直不是很清楚。所以,想做几个实验,彻底解决这个问题。为此,我们设计了三个实验。1、直接引用类变量importosimportsysclassA():data=1......
  • python编程(python和c相互调用)
      通常为了扩展python的功能,我们需要将c库移植到python上面。python和c调用一般分成两种情况,一种是python调用c,这种情况最为普遍,也比较简单。另外一种就是c调用python,这......
  • 21.1 动态TLS--《Windows核心编程》
    应用程序通过调用一组4个函数来使用动态TLS,这些函数实际上最经常为DLL所使用。通常情况下,如果DLL使用TLS,那么当它用DLL_PROCESS_ATTACH标志调用它的DllMain函数时......
  • 21.2 静态TLS--《Windows核心编程》
    部分笔记来自于:https://blog.csdn.net/Steven_programe_life/article/details/103358251?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baiduland......
  • socket通信编程C++实现
    socket提供了套接字,以方便我们想读取文件一样进行网络进程间的数据通信。在网络通信中,套接字一定是成对出现的。一端的发送缓冲区对应对端的接收缓冲区。我们使用同一个文......
  • 20.3 DLL入口函数--《Windows核心编程》
    如果在执行一些与进程或者线程有关的初始化或者销毁工作的时候,需要DllMain。如果只需要创建一个包含资源的DLL,不需要这个函数。B00LWINAPIDllMain(HINSTANCEhinstDll,......
  • 20.4 延迟加载DLL--《Windows核心编程》
    延迟加载的DLL是个隐含链接的DLL,它实际上要等到你的代码试图引用DLL中包含的一个符号时才进行加载。DLL延迟加载技术的原理,就是从导入表中去掉某dll这一项,等到正式调......
  • 20.5 函数转发器/已知的DLL/DLL重定向/模块的基地址重定位--《Windows核心编程》
    一、函数转发器函数转发器是DLL的输出节(导出段)中的一个项目,用于将对一个函数的调用转至另一个DLL中的另一个函数。可以在DLL中使用函数转发器:#pragmacomment(link......