首页 > 编程语言 >Python工具箱系列(三十四)

Python工具箱系列(三十四)

时间:2023-05-29 11:58:41浏览次数:36  
标签:engine Python 数据库 ORM location 三十四 table 工具箱 sensor

SQLAlchemy是著名的ORM(Object Relational Mapping-对象关系映射)框架。其主要作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来。对许多语言(例如JAVA/PYTHON)来说就是定义一个对象,并且这个对象对应着一张数据库的表。而这个对象的实例,就对应着表中的一条记录。

其整体思路如下图所示:

其中类、对象与属性与数据库相关内容的对应关系如下图所示:

ORM的优点:

 

  • 数据模型与代码统一定义,更新与维护简单,代码高度重用一致。

  • ORM有现成的工具,很多功能都可以自动完成,比如表格增删、预处理、事务等。

  • 基于ORM的业务代码比较简单,代码量少,语义性好,容易理解。

  • 你不必编写性能不佳的SQL。

ORM的缺点:

 

  • ORM库多层封装,实现巧妙,需要花很多精力学习和设置。

  • 对于复杂的查询,ORM要么是无法表达,要么是性能不如原生的SQL。

  • ORM抽象掉了数据库层,开发者无法了解底层的数据库操作,也无法定制一些特殊的SQL。

 

 

 从整体上看,ORM节省了开发时间,减少了代码错误的可能性,同时能够方便地在多个数据库间灵活迁移,还是非常值得使用。而在python语言中,SQLAlchemy是著名的ORM框架之一,它的整体架构如下图所示:

从图中可以看出,SQLAIchemy是分层架构,由Core以及ORM两部分组成。其中,Core完成了与数据库操作的各类封闭,是相对低层的。而ORM层则利用Core层的能力进行更宏观的操作。因此,在一段python代码中,使用Core与ORM层同时来操作数据库也是可行的,并不矛盾与冲突。

下面先从最基本的表格创建做起。非ORM编程中,表格的创建无非两个途径:

●基于DBMS本身提供的CLI/GUI界面,发出DDL语句进行数据库/表格本身的增删改查。

●使用语言连接数据库后,发出命令来对数据库/表格进行增删改查。

而由于每种数据库都有自己的方言,所以命令语句各有差异,需要不断地调整。而使用SQLAlchemy则实现了代码统一。例如以下代码在mssql以及mysql上创建表格,并且可以查询表格的元数据,以及插入数据后的查询。

from sqlalchemy import (Column, Integer, MetaData, String, Table,
                        create_engine, text, Float, DateTime, ForeignKey)
from sqlalchemy_utils.functions import create_database, database_exists

configure_pg = {"user": "postgres",
                'password': '88488848',
                'dns': 'dbserver.home',
                "port": 5432,
                'prefix': 'postgresql+psycopg2',
                'postfix': ''
                }

configure_mssql = {"user": "sa",
                   'password': '88488848',
                   'dns': 'dbserver.home',
                   "port": 1433,
                   'prefix': 'mssql+pymssql',
                   'postfix': '?charset=utf8'
                   }

configure_mysql = {"user": "root",
                   'password': '88488848',
                   'dns': 'dbserver.home',
                   "port": 3306,
                   'prefix': 'mysql+mysqlconnector',
                   'postfix': ''
                   }

config = {'mssql': configure_mssql,
          'mysql': configure_mysql, 'postgresql': configure_pg}

database_name = 'testdb'
table_sensor_location = "sensor_location"
table_sensor_data = "sensor_data"


def linkdb(targetstr):
    """
    连接不同的数据库

    Args:
        targetstr (string): 数据库名称

    Returns:
        engine: 用于后续的数据库连接
    """
    if targetstr in config.keys():
        item = config[targetstr]
        connectstring = f"{item['prefix']}://{item['user']}:{item['password']}@{item['dns']}:{item['port']}/{database_name}{item['postfix']}"
        engine = create_engine(connectstring, echo=True, future=True)

    # 如果数据库不存在,则创建之
    if not database_exists(engine.url):
        create_database(engine.url)

    # 做一个测试,不针对任何表
    with engine.connect() as conn:
        result = conn.execute(text("select 'hello world'"))
        print(result.all())
    return engine


def createtbs(connector):
    """"
    创建数据库中的2张表。用于保存传感器数据与传感器本身的信息
    """
    metadata_obj = MetaData()

    # 描述传感器的表
    sensor_location_tb = Table(
        table_sensor_location,
        metadata_obj,
        Column('id', Integer, primary_key=True, autoincrement=False),
        Column('location', String(30), nullable=False)
    )

    # 保存传感器数据的表
    sensor_data_tb = Table(
        table_sensor_data,
        metadata_obj,
        Column('id', Integer, primary_key=True, autoincrement=False),
        Column('sensor_id', ForeignKey(
            f'{table_sensor_location}.id'), nullable=False),
        Column('area', String(30)),
        Column('pm25', Float),
        Column('timestamp', DateTime)
    )
    print(sensor_data_tb.compile())

    # 创建并返回表
    metadata_obj.create_all(connector)
    return sensor_data_tb, sensor_location_tb


def tableinfo(connector, tablename):
    """
    获得指定表名的相关元数据信息

    Args:
        connector (engine): 数据库连接器
        tablename (string): 要查询的表名
    """
    metadata_obj = MetaData()
    some_table = Table(tablename, metadata_obj, autoload_with=connector)
    print([c.name for c in some_table.columns])


def gensonsorinfo(connector):
    with connector.connect() as conn:
        conn.execute(text(f"INSERT INTO {table_sensor_location} (id, location) VALUES (:x, :y)"),
                     [{"x": 1, "y": '1号楼'}, {"x": 2, "y": '2号楼'}])

        conn.commit()

        result = conn.execute(
            text(f"SELECT id, location FROM {table_sensor_location}"))
        for x, y in result:
            print(f"id: {x}  location: {y}")


# 依次连接多个数据库。从而验证代码的一致性
for dbname in config.keys():
    con = linkdb(dbname)
    createtbs(con)
    tableinfo(con, table_sensor_data)
    tableinfo(con, table_sensor_location)
    gensonsorinfo(con)

从代码可以看出,可以用统一的访问方式来操作mssql/mysql/postgresql三种数据库。而且,以上方式与前文中的基于游标的写法类似。

 

标签:engine,Python,数据库,ORM,location,三十四,table,工具箱,sensor
From: https://www.cnblogs.com/shanxihualu/p/17440033.html

相关文章

  • python:yaml模块
    python:yaml模块https://www.jianshu.com/p/eaa1bf01b3a6https://www.runoob.com/w3cnote/yaml-intro.html......
  • Python压缩JS文件,重点是 slimit
    摘要:PythonWeb程序员必看系列,学习如何压缩JS代码。本文分享自华为云社区《Python压缩JS文件,PythonWeb程序员必看系列,重点是slimit》,作者:梦想橡皮擦。本篇博客将学习压缩JS代码,首先要学习的模块是jsmin。jsmin库Python中的jsmin库来压缩JavaScript文件。这个库......
  • Python连接Redis
    1、操作模式redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。 2、连接池redis-py使用connectionpool来管理对一个redisserver的所有连接,避免......
  • 《最新出炉》系列初窥篇-Python+Playwright自动化测试-1-环境准备与搭建
    1.简介有很多人私信留言宏哥问能不能介绍一下Playwright这款自动化神器的相关知识,现在网上的资料太少了。其实在各大博客和公众号也看到过其相关的介绍和讲解。要不就是不全面、不系统,要不就是系统全面但是人家是收费的。当然了宏哥接下来也可能介绍的不全面或者不系统,能力有限望......
  • Python generator 构建协程,实现异步编程(使用yield构建消息处理者和消息创造者)
    协程的定义理解Python协程可以在单个处理机或多个处理机上运行,这取决于具体实现方式。在Python中,主要有两种协程实现方式:生成器协程和asyncio协程。生成器协程只能在单个处理机上运行,因为生成器协程是通过生成器函数实现的,而生成器函数在单个线程中执行。生成器协程也称为......
  • pytorch1.4.0 CUDA11.0 python3.7安装记录
    参考过程CUDA安装教程CUDA教程2找到自己电脑显卡的cuda版本CUDA是什么版本是11.0.140安装CUDA11.1下载链接,但是我们不用这个我们用的是11.0最新版的下载地址下载选项设置(害,整整2个多G啊)。可以在下载按钮的地方右键,复制链接,然后在迅雷下面下载。虽然慢但是稳定。不过用Chrome复......
  • 聊聊Python内函数的参数
    引:基于函数的定义与调用两个阶段,函数的参数也由此分为两块:形式参数和实际参数 形参与实参介绍函数的参数分为形式参数和实际参数,简称形参和实参:形参即在定义函数时,括号内声明的参数,形参本质就是一个变量名,用来接收外部传来的值;实参即在调用函数时,括号内传入的值,值可以是常......
  • python3身份证校验
    python3身份证校验看到有朋友发了一个专门的身份证校验,就很感兴趣,好奇是什么原理。百度了下计算规则,发现python也可以实现。来源地址在线身份证校验py3实现实际上就是根据身份证前17位,计算求和,然后取余找到对应的校验码。#身份证计算规则#身份证号码最后一位随便填......
  • python+playwright 学习-66 highlight 调试定位时高亮显示元素
    前言highlight()方法是通过高亮显示元素,在调试中有很大优势,可以清楚看到定位的元素所在的位置遇到的问题使用示例:点百度页面,定位文本元素“新闻”后点击fromplaywright.sync_apiimportsync_playwright#上海悠悠wx:283340479#blog:https://www.cnblogs.com/yoyoket......
  • python3.10版本以后使用asyncio不报错方法
    importasyncioimporttimeasyncdeffunc1():print(1)awaitasyncio.sleep(2)print(2)asyncdeffunc2():print(3)awaitasyncio.sleep(2)print(4)asyncdefmain():task=[asyncio.ensure_future(func1()),asy......