Python实现ORM

Python实现ORM

ORM全称Object-Relational Mapping,简单的理解就是通过代码的方式操作数据库。ORM 的出现让我们不用关心 SQL 而用自己熟悉的编程语言来操作数据库。在Python开发中,ORM框架也是非常常见的,比如Django自带的ORM,SQLAlchemy等。

ORM的基本概念

建立连接

在使用ORM之前,需要首先建立与数据库的连接。可以使用Python的标准库sqlite3进行测试。

import sqlite3

# 连接数据库
conn = sqlite3.connect('test.db')
print('Opened database successfully')

定义模型

在使用ORM时,需要先定义模型。模型是一个面向对象的类,对应数据库中的一张表。类中的属性对应着表中的列。很多ORM框架都支持简便的语法来定义模型,比如Django的models.py文件。

class User:
    def __init__(self, id, name, age):
        self.id = id
        self.name = name
        self.age = age

操作数据库

ORM提供了常用的CRUD操作(Create、Read、Update、Delete)。

创建表

需要为模型创建对应的数据库表。

c.execute('''CREATE TABLE USER
       (ID INT PRIMARY KEY     NOT NULL,
       NAME           TEXT    NOT NULL,
       AGE            INT     NOT NULL);''')

插入数据

可以通过ORM向表中插入数据。

user = User(1, 'Alice', 18)
conn.execute("INSERT INTO USER (ID,NAME,AGE) \
      VALUES (?, ?, ?)", (user.id, user.name, user.age))

查询数据

可以通过属性来查询数据。

cursor = conn.execute("SELECT id, name, age from USER")
for row in cursor:
  user = User(row[0], row[1], row[2])
  print(f"ID = {user.id}, NAME = {user.name}, AGE = {user.age}")

更新数据

可以修改已有的数据。

user.age = 20
conn.execute("UPDATE USER set AGE = ? where ID = ?", (user.age, user.id))

删除数据

可以删除指定的数据。

conn.execute("DELETE from USER where ID = ?", (user.id,))

实现ORM的基本框架

ORM的实现思路:

  1. 将每个类定义为python类,类中的属性对应着表中的列
  2. 定义一个基础的Model类,所有的类继承这个类
  3. 在基础的Model类中为类动态的添加增、删、改、查四个方法

下面我们来实现这个框架。

类的映射

我们可以为每一个表定义对应的类。

class User(Model):
    __table__ = 'USER'

    id = IntegerField('ID', primary_key=True)
    name = StringField('NAME')
    age = IntegerField('AGE')

其中,__table__表示对应的表名,__primary_key__表示主键,IntegerField和StringField是两个常用的属性类型。

创建连接

import sqlite3

conn = sqlite3.connect('test.db')

Field类

我们可以将每个字段抽象成一个类,包括字符型、数值型等不同的类型。

class Field:
    pass

class StringField(Field):
    def __init__(self, name):
        self.name = name

class IntegerField(Field):
    def __init__(self, name):
        self.name = name

Model类 & 增删改查

在基础的Model类中为类动态的添加新增、删除、查询和更新四个方法。

class Model:
    @classmethod
    def create_table(cls):
        fields = []
        for k, v in cls.__dict__.items():
            if isinstance(v, Field) and v.primary_key is True:
                field = k + " " + v.field_type + " PRIMARY KEY"
                fields.append(field)
            elif isinstance(v, Field):
                field = k + " " + v.field_type
                fields.append(field)
        field_str = ", ".join(fields)
        table_name = cls.__table__
        create_sql = f"CREATE TABLE {table_name} ({field_str})"
        conn.execute(create_sql)

    def save(self):
        fields = []
        values = []
        for k, v in self.__dict__.items():
            if isinstance(v, Field) and v.primary_key is not True:
                fields.append(k)
                values.append(v)
        field_str = ", ".join(fields)
        value_str = ", ".join(["?" for _ in range(len(fields))])
        table_name = self.__table__
        insert_sql = f"INSERT INTO {table_name} ({field_str}) VALUES ({value_str})"
        conn.execute(insert_sql, values)
        conn.commit()

    @classmethod
    def get_one(cls, pk):
        table_name = cls.__table__
        pk_field = None
        for k, v in cls.__dict__.items():
            if isinstance(v, Field) and v.primary_key is True:
                pk_field = k
        select_sql = f"SELECT * FROM {table_name} WHERE {pk_field}=?"
        cursor = conn.execute(select_sql, (pk, ))
        row = cursor.fetchone()
        if row is None:
            return None
        values = [row[i] for i in range(len(row))]
        obj = cls()
        for k, v in obj.__dict__.items():
            if isinstance(v, Field) and v.primary_key is True:
                setattr(obj, k, values.pop(0))
            elif isinstance(v, Field):
                setattr(obj, k, values.pop(0))
        return obj

    def update(self):
        fields = []
        values = []
        pk_field = None
        for k, v in self.__dict__.items():
            if isinstance(v, Field) and v.primary_key is not True:
                fields.append(k + "=?")
                values.append(v)
            elif isinstance(v, Field) and v.primary_key is True:
                pk_field = k
        values.append(getattr(self, pk_field))
        field_str = ", ".join(fields)
        table_name = self.__table__
        update_sql = f"UPDATE {table_name} SET {field_str} WHERE {pk_field}=?"
        conn.execute(update_sql, values)
        conn.commit()

    def delete(self):
        pk_field_name = None
        for k, v in self.__dict__.items():
            if isinstance(v, Field) and v.primary_key is True:
                pk_field_name = k
        pk_val = getattr(self, pk_field_name)
        table_name = self.__table__
        delete_sql = f"DELETE FROM {table_name} WHERE {pk_field_name}=?"
        conn.execute(delete_sql, (pk_val, ))
        conn.commit()

在使用的时候,可以通过继承Model类来实现增删改查的功能。

class User(Model):
    __table__ = 'USER'
    id = IntegerField('ID', primary_key=True)
    name = StringField('NAME')
    age = IntegerField('AGE')

    def __init__(self, id, name, age):
        self.id = id
        self.name = name
        self.age = age

User.create_table()

user1 = User(1, 'Alice', 18)
user2 = User(2, 'Bob', 20)
user3 = User(3, 'Cindy', 22)

# 插入
user1.save()
user2.save()
user3.save()

# 查询
user = User.get_one(1)
print(f"id: {user.id}, name: {user.name}, age: {user.age}")

# 更新
user.age = 20
user.update()

# 删除
user.delete()

总结

ORM是非常常用的技术,比如在Django、Flask、SQLAlchemy等框架中都有非常完善的ORM。实现一个简单的ORM可以帮助我们更好的理解ORM的底层实现原理,从而更好地应对一些较为复杂的业务场景。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python实现ORM - Python技术站

(0)
上一篇 2023年3月28日
下一篇 2023年3月28日

相关文章

  • WxJava微信公众号开发入门实战

    WxJava是一个Java语言开发的微信公众号SDK,我们可以使用它快速开发微信公众号应用。下面是WxJava微信公众号开发的完整攻略。 1. 准备工作 在开始微信公众号开发前,我们需要完成以下准备工作: 注册微信公众平台账号; 成为微信公众平台开发者; 创建测试公众号; 获取微信公众号的AppID和AppSecret; 下载并导入WxJava SDK。 2…

    other 2023年6月27日
    00
  • vue如何使用原生高德地图你知道吗

    当使用Vue框架并且需要在应用中使用高德地图时,可以通过以下步骤来使用原生高德地图: 步骤 1: 引入高德地图 JavaScript API 首先,在Vue项目中引入高德地图 JavaScript API,可以参照以下方式: <script type="text/javascript" src="//webapi.amap…

    other 2023年6月27日
    00
  • 删除电脑右键菜单中映射网络驱动器选项的方法

    删除电脑右键菜单中映射网络驱动器选项的方法 在 Windows 操作系统中,我们可以通过右键菜单来映射网络驱动器。然而,有时候这个选项并不常用,或者我们想要删除它,本文将为大家介绍删除电脑右键菜单中映射网络驱动器选项的方法。 步骤一:打开注册表编辑器 首先,我们需要打开注册表编辑器。按下快捷键 Win + R,输入 regedit,回车打开注册表编辑器。 步…

    other 2023年6月27日
    00
  • C++ 面试题目(整理自牛客网)

    首先我们需要明确该面试题目整理自牛客网,也就是说,可以参考一些牛客网上的题解或解析,从而得到更好的答案。当然,最好还是自己能够熟练掌握相关知识,并进行实际的练习。下面,我将为大家详细讲解这个面试题目的攻略。 1. 了解面试题目的背景和目标 在准备面试题目前,首先要了解这个面试题目的背景和目标。这道题目涵盖了许多C++的基础知识,如指针、堆栈、内存管理、STL…

    other 2023年6月27日
    00
  • 判断Linux Shell环境变量是否存在

    判断Linux Shell环境变量是否存在的完整攻略如下: 1. 使用echo命令检测环境变量是否存在 可以使用echo命令来检测环境变量是否存在,具体操作如下: if [ -n "$SHELL" ]; then echo "SHELL exists" else echo "SHELL does not ex…

    other 2023年6月27日
    00
  • MyBatis 接收数据库中没有的字段的解决

    MyBatis是一种优秀的持久层框架,它可以很好地解决Java应用程序中与数据库打交道的操作,支持SQL编写和ORM框架两种开发方式。然而有时候我们会碰到数据库表中新增了字段,但对应的Java实体类没有相应更新的情况,那么我们该如何在MyBatis中处理这种情况呢?下面是针对这种情况的完整攻略。 解决方案 方案一:在查询语句中手动忽略掉没有的字段 我们可以在…

    other 2023年6月25日
    00
  • mongodb(实现join)

    以下是关于“MongoDB(实现JOIN)”的完整攻略: MongoDB简介 MongoDB是一个开源的文档型数据库,使用JSON格式存储,支持动态查询和索引MongoDB的特点是高性能、高可用性、易扩展、灵活性高等。 MongoDB的JOIN MongoDB不支持传统SQL JOIN操作,但是可以通过一些技巧来实现类似的功能。以下是两种实现JOIN的方法:…

    other 2023年5月9日
    00
  • Java多线程——Semaphore信号灯

    Java多线程——Semaphore信号灯的完整攻略 Semaphore是Java多线程中的一种同步工具,用于控制同时访问某个资源的线程数量。Semaphore维护了一个许可证集合,线程在访问资源前必须先获取许可证,访问完毕后释放许可证。本文将详细讲解Semaphore的使用方法和功能,包括两个示例说明。 Semaphore的作用 Semaphore的作用是…

    other 2023年5月5日
    00
合作推广
合作推广
分享本页
返回顶部