python编程(orm原理和实践)

栏目: Python · 发布时间: 6年前

内容简介:python编程(orm原理和实践)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

网上关于python orm介绍的文章很多,但是我觉得廖雪峰这个orm是介绍的最好的。下面,我就给出自己对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='test@orm.org', 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='test@orm.org', password='my-pwd')
u.save()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法的乐趣

算法的乐趣

王晓华 / 人民邮电出版社 / 2015-4 / 79.00元

算法之大,大到可以囊括宇宙万物的运行规律;算法之小,小到寥寥数行代码即可展现一个神奇的功能。算法的应用和乐趣在生活中无处不在: 历法和二十四节气计算使用的是霍纳法则和求解一元高次方程的牛顿迭代法; 音频播放器跳动的实时频谱背后是离散傅立叶变换算法; DOS时代著名的PCX图像文件格式使用的是简单有效的RLE压缩算法; RSA加密算法的光环之下是朴实的欧几里德算法、蒙哥马利算......一起来看看 《算法的乐趣》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具