python-27-Python ORM系列之彻底搞明白ORM概念,对ORM进行封装结合FastAPI实现数据库的增删改查,联表查询等接口
一.简介
在Python基础系列ORM部分为大家介绍了如何搭建MySQL数据和MySQL一些访问配置,同时也介绍了pymysql库的封装来实现对数据库的增删改查功能,但是截止以上都没有实现ORM,好菜已经上来 这一篇文章来帮助大家彻底掌握ORM框架,并且对ORM进行封装,利用ORM和FASTAPI实现数据库的增删改查,开始我们今天的日拱一卒!
二.安装pymysql、sqlalchemy、fastapi、uvicorn
#使用豆瓣源安装 提升安装速度
pip install pymysql -i http://pypi.doubanio.com/simple --trusted-host pypi.doubanio.com
pip install sqlalchemy -i http://pypi.doubanio.com/simple --trusted-host pypi.doubanio.com
pip install fastapi -i http://pypi.doubanio.com/simple --trusted-host pypi.doubanio.com
pip install uvicorn -i http://pypi.doubanio.com/simple --trusted-host pypi.doubanio.com
pymysql:Python 实现的 MySQL 数据库连接库
本文示例是调用MySql数据库,如果需要切换其他数据库,可以下载对应插件和改变ORM对应的连接字符串即可
MySQL-Python
mysql+mysqldb://:@[:]/pymysql
mysql+pymysql://:@/[?]MySQL-Connector
mysql+mysqlconnector://:@[:]/cx_Oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value…]
SQLAlchemy:Python ORM(对象关系映射)工具
fastapi:FastAPI 是一个现代的、快速的 web 框架,用于构建 API
Uvicorn:Uvicorn 是一个高性能的 ASGI 服务器,适用于运行 FastAPI 和其他支持 ASGI 的 Python web 框架。
三.ORM基础介绍
1.首先我们需要sqlalchemy 多个不同模块和库,常用的引入如下
from sqlalchemy import create_engine,Column, Integer, String, ForeignKey,DateTime,Boolean,Text
from sqlalchemy.ext.declarative import declarative_base #orm基类
from sqlalchemy.orm import sessionmaker,relationship,joinedload
create_engine
:创建数据库连接引擎。
Column
, Integer
, String
, ForeignKey
, DateTime
, Boolean
, Text
:用来定义数据库表的字段类型和约束。
declarative_base
:创建 ORM 基类,供模型类继承。
sessionmaker
:创建数据库会话,执行数据库操作。
relationship
:定义表之间的关系。
joinedload
:优化查询,避免 N+1 查询问题。
四.构建数据库连接字符串的配置文件
4.1创建配置文件db_config.ini
在当前项目中创建config文件夹,在文件夹下db_config.ini文件,作为我们的数据库配置文件,内容如下:
[localdb]
host = localhost
user = root
password = yourpsw
port = 3306
database = myurlhub
4.2创建获取配置文件工具包
在当前项目中创建utils文件夹,新建__init__.py
文件,里面不用写任何东西,在utils文件夹下新建config_helper.py文件,用来帮助我们获取配置文件信息,文件内容如下:
import configparser
class Config(object):
def __init__(self, filename, encoding='UTF-8'):
# 声明配置类对象
self.config = configparser.ConfigParser()
# 读取配置文件
self.config.read(filename, encoding)
def get_value(self, section, option):
"""获取 value"""
value = self.config.get(section, option)
return value
def get_items(self, section):
value = dict(self.config.items(section))
return value
# 读取配置文件
# config.read(fileName, 'GBK')
# print(f"sections: {config.sections()}")
# print(f"options: {config.options('localdb')}")
# print(f"items: {config.items('localdb')}")
我们的整体结构文件:
五.读取配置文件数据 构建数据库连接引擎
在当前项目文件夹utils中 新建orm_helper.py文件作为 ORM 帮助类库,我们需要根据配置文件来构建连接字符串,从而创建我们的ORM据库连接引擎 engine = create_engine(mysql_conn_str)
orm_helper.py 目前的代码:
#orm_helper.py
from sqlalchemy import create_engine,Column, Integer, String, ForeignKey,DateTime,Boolean,Text
from sqlalchemy.ext.declarative import declarative_base #orm基类
from sqlalchemy.orm import sessionmaker,relationship,joinedload
from utils import config_helper
import os
from datetime import datetime
import uuid
'''
数据库连接拼接串语法:
'''
# 加载数据库配置
__config_file_path = os.path.join(os.getcwd(),'config\db_config.ini')
__config = config_helper.Config(__config_file_path,'UTF-8')
__localdb = __config.get_items('localdb')
mysql_conn_str = f"mysql+pymysql://{
__localdb['user']}:{
__localdb['password']}@{
__localdb['host']}:{
__localdb['port']}/{
__localdb['database']}"
engine = create_engine(mysql_conn_str)
六.创建 ORM 基类,公共基类,用来定义数据库表的字段类型和约束的类
创建ORM模型的基类,公共字段基类,用于一键生成数据库对应的表字段
-
实现ORM基类:后续用来定义数据库表的字段类型和约束的类都要继承ORM的基类
我们本次 要创建2个数据库表 都要继承ORM Base基类CommonFieldsMixin公共字段类,CommonFieldsMixin公共字段类,所有表都有的字段,不需要额外实现,直接继承实现
Base = declarative_base() # 我们本次 要创建2个数据库表 都要继承ORM Base基类 CommonFieldsMixin为公共字段类,为所有表都有的字段,不需要额外实现 # 创建用户表 #class MUH_User(Base,CommonFieldsMixin): #创建用户登录密码表 #class MUH_User_Psw(Base,CommonFieldsMixin):
-
实现与数据库关联的ORM表的类:这些类后续为ORM操作的对象,我们就可像操作对象一样操作这2个类与数据库进行关联,而不需要关心SQL实现
因为我们需要实现用户注册,故要创建2张表 用户表 和 用户密码表,一张保存用户基础信息,一张保存用户密码表
注意有几个细节:
-
创建公共基类CommonFieldsMixin,让所有的表都自动包含公共基类字段
class MUH_User(Base,CommonFieldsMixin): class MUH_User_Psw(Base,CommonFieldsMixin)
其中Base 是ORM基类 CommonFieldsMixin为公共基类
ORM类定义说明:
create_date = Column(DateTime, default=datetime.now())
-
create_date:对应数据库表的列名
-
Column:表示列
-
DateTime:数据类型,注意数据库表的类型都是基础类型,千万别搞个列表,字典,元组作为表的类型,如果非要用请转换为JSON string类型
-
default:默认值
-
ORM中常见类型约束及其他约束整理如下
ORM表中列的类型 说明 举例 Integer 整数类型的字段 age = Column(Integer) String(length) 描述变长字符串类型的字段 name = Column(String(50)) Text 用于存储较长文本 description = Column(Text) Boolean 描述布尔值类型的字段 is_active = Column(Boolean, default=True) Float 描述浮点数类型的字段 price = Column(Float) Numeric(precision, scale) 精确数字类型,适用于需要高精度的小数 amount = Column(Numeric(10, 2)) #精度为 10 位,保留 2 位小数的数字 Date 描述日期类型字段,不包含时间部分 birthdate = Column(Date) DateTime 描述日期和时间类型字段 created_at = Column(DateTime) Time 描述时间类型字段,不包含日期部分 clock_in = Column(Time) Interval 描述时间间隔字段,用于存储持续时间(例如,2 days, 5 hours) duration = Column(Interval) UUID 用于存储 UUID
(通用唯一标识符)user_id = Column(UUID(as_uuid=True), default=uuid.uuid4) LargeBinary(不建议使用) 描述二进制数据字段,适用于存储大块二进制数据,如文件或图像。 image = Column(LargeBinary) Enum 用于存储枚举类型字段,通常用于有限的固定选项(如性别、状态等) size = Column(Enum(‘small’, ‘medium’, ‘large’, name=‘size’)) JSON 用于存储 JSON 格式的数据 preferences = Column(JSON) ForeignKey 用于指定外键约束,表示该列是另一个表的外键 user_id = Column(Integer, ForeignKey(‘users.id’)) primary_key 定义表的主键 id = Column(String(50), primary_key=True, default=str(uuid.uuid4())) nullable 是否可为null name = Column(String(100), nullable=False) default 默认值 id = Column(String(50), primary_key=True, default=str(uuid.uuid4())) onupdate 当更新默认值 onupdate=datetime.utcnow
创建公共基类
#orm_helper.py #公共基类 # 定义公共字段 Mixin 类 class CommonFieldsMixin: create_date = Column(DateTime, default=datetime.now()) create_id = Column(String(50)) update_date = Column(DateTime, default=datetime.now(), onupdate=datetime.now) update_id = Column(String(50)) visible = Column(Boolean, default=True) descriptions = Column(Text)
-
-
所有的id 采用guid字符串来实现,故引入
import uuid
,默认自动生成
id = Column(String(50), primary_key=True,default=uuid.uuid4())
#orm_helper.py # 创建用户表 class MUH_User(Base,CommonFieldsMixin): __tablename__ = "muh_user" id = Column(String(50), primary_key=True,default=str(uuid.uuid4())) user_name = Column(String(20)) user_gender = Column(String(2)) user_age = Column(Integer) user_imgs =Column(String(255)) def __repr__(self): # 自动列出所有字段 attrs = { column.name: getattr(self, column.name) for column in self.__table__.columns} return f"<{ self.__class__.__name__}({ ', '.join(f'{ key}={ value!r}' for key, value in attrs.items())})>" #创建用户登录密码表 class MUH_User_Psw(Base,CommonFieldsMixin): __tablename__ = "muh_user_psw" id = Column(String(50), primary_key=True,default=str(uuid.uuid4())) user_id = Column(String(50)) user_psw = Column(String(255)) def __repr__(self): # 自动列出所有字段 attrs = { column.name: getattr(self, column.name) for column in self.__table__.columns} return f"<
-