您好,欢迎来到网暖!

当前位置:网暖 » 站长资讯 » 建站基础 » 网络技术 » 文章详细 订阅RssFeed

【py3】使用元类模拟ORM

来源:网络整理 浏览:329次 时间:2022-12-01

什么是元类?



先看下列代码,对象 s 是由类Student创建的,那么Student类又是由谁创建的呢?答案就是元类type,元类就是用来创建类的类。


class Student():
    pass
s = Student()
print(s.__class__, s.__class__.__class__)
--------------------------------------------------
<class '__main__.Student'> <class 'type'>
以上代码等价于直接由type创建目标类,只需在type中传入类名,继承的类元组,类属性字典即可。注意这里的 t 代表的是类Master,而非对象。
t = type("Master", (object,), {})
print(t.__class__)
--------------------------------------------------
<class 'type'>

什么是ORM?



ORM是对象关系映射,对象通常就是指实体对象,关系通常就是指关系型数据库表,就是从代码对象映射到数据库表,即操作对象完成数据库表的操作。ORM是python后端web框架Django的核心思想,下面简单模拟下orm。

对象创建过程



python中对象的创建是分为创建和初始化两步的,首先调用__new__方法创建对象,然后调用__init__完成对象初始化。

class Student(object):
  def __new__(cls, *args, **kwargs):
    print("创建对象...")
    return super().__new__(cls)
    def __init__(self):
    print("初始化...")
    self.age = "15"
if __name__ == '__main__':
    s = Student()
--------------------------------------------------
创建对象...
初始化...

使用元类操作类



我们很少直接使用__new__方法,因为很少去操控类的创建,元类是创建类的超类,所以我们可以在元类的__new__方法中完成对目标类的操控。以下我们使用元类完成对象单例模式。


class Singleton(type):
  def __new__(mcs, class_name, class_bases, class_attrs):
    class_attrs['instance'] = None
    return type.__new__(mcs, class_name, class_bases, class_attrs)
  def __call__(cls, *args, **kwargs):
    if cls.instance is None:
      cls.instance = super(Singleton, cls).__call__(*args, **kwargs)
    return cls.instance

class Car(object, metaclass=Singleton):
    pass
if __name__ == '__main__':
    s = Car()
    t = Car()
    print(id(s), id(t))
--------------------------------------------------
31498640 31498640

使用元类实现ORM



上面我们已经看到了使用元类可以操作目标类,下面我们使用元类完成数据库表操作,先创建一个实体对象类。


class User(Model, metaclass=BaseModel):
    _table = 't_user'
    name = 'u_name'
    age = 'u_age'

使用元类收集对象映射的表名,字段名称及值。注意一个类有许多内置属性,收集属性时只收集自定义属性,其中表名我们约定使用下划线开头,优秀的框架都有自己的约定,约定优于配置。
class BaseModel(type):
    def __new__(mcs, class_name, class_bases, class_attrs):
        print(mcs, class_name, class_bases, class_attrs)
        tmp = dict()
        for k, v in class_attrs.items():
            if not str(k).startswith('_'):
                tmp[k] = v
        class_attrs['mapping'] = tmp
        class_attrs['table'] = class_attrs['_table']
        return type.__new__(mcs, class_name, class_bases, class_attrs)
我们把通用的操作抽象到一个基类中,在初始化时将传入的所有关键字参数初始化到实例属性中。这里以保存为例,收集字段名称和字段对应的数值,然后组装SQL,这样就完成了将对象操作映射到数据库表。
class Model(object):
    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)
    def save(self):
        cloumns = []
        values = []
        for k, v in self.mapping.items():
            cloumns.append(v)
            values.append(getattr(self, k, None))
        tmp = []
        for v in values:
            if isinstance(v, str):
                tmp.append("""'%s'""" % v)
            else:
                tmp.append(str(v))
    sql = 'insert into %s (%s) values (%s)'% (self._table, ','.join(cloumns), ','.join(tmp))
    print("mapping sql: %s" % sql)

测试:



if __name__ == '__main__':
    u = User(name='码农小麦', age=25)
    u.save()
print('-'*50)
--------------------------------------------------
mapping sql: insert into t_user (u_name,u_age) values ('码农小麦',25)


推荐站点

  • 腾讯腾讯

    腾讯网(www.QQ.com)是中国浏览量最大的中文门户网站,是腾讯公司推出的集新闻信息、互动社区、娱乐产品和基础服务为一体的大型综合门户网站。腾讯网服务于全球华人用户,致力成为最具传播力和互动性,权威、主流、时尚的互联网媒体平台。通过强大的实时新闻和全面深入的信息资讯服务,为中国数以亿计的互联网用户提供富有创意的网上新生活。

    www.qq.com
  • 搜狐搜狐

    搜狐网是全球最大的中文门户网站,为用户提供24小时不间断的最新资讯,及搜索、邮件等网络服务。内容包括全球热点事件、突发新闻、时事评论、热播影视剧、体育赛事、行业动态、生活服务信息,以及论坛、博客、微博、我的搜狐等互动空间。

    www.sohu.com
  • 网易网易

    网易是中国领先的互联网技术公司,为用户提供免费邮箱、游戏、搜索引擎服务,开设新闻、娱乐、体育等30多个内容频道,及博客、视频、论坛等互动交流,网聚人的力量。

    www.163.com
  • 新浪新浪

    新浪网为全球用户24小时提供全面及时的中文资讯,内容覆盖国内外突发新闻事件、体坛赛事、娱乐时尚、产业资讯、实用信息等,设有新闻、体育、娱乐、财经、科技、房产、汽车等30多个内容频道,同时开设博客、视频、论坛等自由互动交流空间。

    www.sina.com.cn
  • 百度一下百度一下

    百度一下,你就知道

    www.baidu.com