Python操作Mysql基础与ORM

文章目录

    • 前言:
    • Python基础操作Mysql
    • ORM操作MySQL
      • 创建/删除数据库
      • 新增数据
      • 索引/基础/条件查询
      • 函数/多表/分组/去重/排序/分页
      • 更改/删除

前言:

无聊顺便把慕课的操作三大数据库看了

链接贴上: https://coding.imooc.com/class/chapter/507.html

三大常见的数据库,每次去操作要去翻看文档就很烦

然后就简单写了几个实战的脚本,看代码就知道该怎么做了

因为情况很多,万变不离其中,我就没封装成面向对象

(一部分是要考虑很多种情况,其次是相当于复习加固就是懒得写)

今天先发Mysql的,因为其他的我还在写~

首发于 https://sleepymonster.cn

Python基础操作Mysql

其实最主要的是会用%s写数据进去 我记得原来往数据库里面写图片来着 转了格式 最后用%s写进入的

$ pip install mysql-connector-python

$ pip install mariadb
 
$ pip install mysqlClient

$ pip install PyMySQL # 这个是主要使用的
from pymysql import connect, Error
from pymysql.cursors import DictCursor

#  建立连接
#  返回的是一个对象
try:
    connect = connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='',
        database='go_gateway_test',
        cursorclass=DictCursor  # 是否开启以字典的形式返回(不要这行就是元组)
    )
    with connect:  # 在with下会自动关闭免去connect.close
        with connect.cursor() as cursor:  # 建立游标
            sql = 'SELECT * From gateway_service_info;'
            cursor.execute(sql)  # 执行sql语句
            # 获取查询结果
            for each in cursor:
                print(each)  # (34, 0, 'websocket_test', 'websocket_test', 1)

            # 检索一条数据
            oneData = cursor.fetchone()
            print(oneData)
            another = cursor.fetchone()  # 会在上面的基础上继续取
            print(oneData)

            # 检索全部
            allData = cursor.fetchall()
            for each in allData:
                print(each)

            # 检索指定数量的数据
            dataList = cursor.fetchmany(10)
            for each in dataList:
                print(each)

            # 防止造成sql注入 采用%s的形式写入
            sql = "SELECT * From gateway_service_info where id = %s"
            cursor.execute(sql, (34,))
            for each in cursor:
                print(each)

            # 修改操作
            sql = "UPDATE gateway_service_info SET load_type = 1 where id = 34;"
            cursor.execute(sql)
            connect.commit()  # 必须要提交事务

            # 插入操作
            load_type = 1
            service_name = 'ServiceName'
            sql = "INSERT INTO `gateway_service_info`(`load_type`, `service_name`) VALUES (%s, %s)"
            cursor.execute(sql, (load_type, service_name))
            connect.commit()  # 必须要提交事务

            # 批量插入
            # sql语句的构造我这里就不写了
            sql1 = "INSERT INTO `gateway_service_info`(`load_type`, `service_name`) VALUES (1, 'ServiceName1')"
            sql2 = "INSERT INTO `gateway_service_info`(`load_type`, `service_name`) VALUES (2, 'ServiceName2')"
            connect.begin()  # 开始事务
            try:
                cursor.execute(sql1)
                cursor.execute(sql2)
                connect.commit()
            except Exception as e:
                connect.rollback()  # 出现错误,开始回滚

            # 删除
            sql = "DELETE FROM gateway_service_info WHERE id = %s"
            cursor.execute(sql)
            connect.commit()  # 必须要提交事务

            # 批量增加
            sql = "INSERT INTO `gateway_service_info`(`load_type`, `service_name`) VALUES (%s, %s)"
            args = ((1, "ServiceName"), (2, "ServiceName"))
            cursor.executemany(sql, args)
except Error as e:
    print('连接失败:{}'.format(e))

ORM操作MySQL

直接用的面向对象的思想,减少SQL语句的书写

下面我直接拆开(怕是GORM一家人)都是能跑的

大部分意思我都写再了注释里面,从上往下看基本都能掌握,没啥弯弯绕绕的

$ pip install SQLAlchemy

创建/删除数据库

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Enum, SmallInteger, Boolean, ForeignKey, \
    select, func, update, delete
from sqlalchemy.orm import declarative_base, relationship, backref, Session
from sqlalchemy.types import CHAR
from sqlalchemy.dialects.mysql import TINYINT
from datetime import datetime
from enum import IntEnum

# 声明一个连接
userName = 'root'
password = ''
host = '127.0.0.1'
port = 3306
database = 'go_gateway_test'
engine = create_engine(f'mysql+pymysql://{userName}:{password}@{host}:{port}/{database}?charset=utf8', echo=True, future=True)

# 声明ORM的一个基类并建立映射关系
Base = declarative_base()


class SexEnum(IntEnum):
    MAN = 1
    WOMEN = 2


# name为在数据库表中的名称
# type为数据类型
# comment为注释
# nullable为不能为空
# default为默认字段
# unique为唯一约束
class User(Base):
    """用户信息表格"""
    __tablename__ = 'account_user'
    id = Column(Integer, name='id', primary_key=True)
    user_name = Column(String(32), nullable=True, name='user_name', comment="user_name", unique=True)
    password = Column(String(512), nullable=True, name='password', comment="password")
    real_name = Column(String(16), nullable=False, name='real_name', comment="real_name")
    sex = Column(Enum(SexEnum), default=None, name='sex', comment="sex")
    age = Column(TINYINT(unsigned=True), default=0, name='age', comment="age")
    create_at = Column(DateTime, default=datetime.now(), name='create_at', comment="create_at")
    is_valid = Column(Boolean, default=True, name='is_valid', comment="is_valid")
    profile = relationship('UserProfile', backref='user', uselist=False)  # 一对一


class UserAddress(Base):
    """地址信息表格"""
    __tablename__ = 'account_user_address'
    id = Column(Integer, name='id', primary_key=True)
    area = Column(String(256), nullable=False, name='area', comment="area")
    phone_num = Column(CHAR(11), name='phone_num', comment="phone_num")
    remark = Column(String(512), name='remark', comment="remark")
    is_valid = Column(Boolean, default=True, name='is_valid', comment="is_valid")

    create_at = Column(DateTime, default=datetime.now(), name='create_at', comment="create_at")
    # user_id = Column(Integer, ForeignKey(User.id), comment="关联")  # 进行ORM关联一对多
    user_id = Column(Integer, ForeignKey(User.id, ondelete="CASCADE"), comment="关联")  # 进行ORM关联一对多,操作一:指定删除后操作

    # user = relationship("User", backref='address')  # 一对多经典
    # user = relationship("User", backref=backref('address', lazy='dynamic'))  # 可以执行子查询
    user = relationship("User", backref=backref('address', lazy='dynamic', cascade="all,delete"))  # 可以执行子查询 操作二:指定删除后操作


class UserProfile(Base):
    """用户详细信息表格"""
    __tablename__ = 'account_user_profile'
    id = Column(Integer, primary_key=True)
    hobby = Column(String(255), nullable=False, name='hobby', comment="hobby")
    user_id = Column(Integer, ForeignKey(User.id), comment="user_id")
    # user = relationship("User", backref=backref('profile', unelist=False))  # 两种方法


# 同步关系创建/删除数据库
# Base.metadata.create_all(engine)  # 创建表
# Base.metadata.drop_all(engine)  # 删除表

新增数据

# 新增数据
# 构建一个对象
userObj = User(
    user_name='Jack' + str(datetime.now()),
    password='123456',
    real_name='杰克',
    sex=1
)
# 添加到session
session = Session(bind=engine, future=True)
session.add(userObj)  # 添加一个
# session.add_all([userObj, userObj])  # 添加多个
session.commit()

# 这个部分有点难 理清楚顺序
# 根据一对一,一对多的关系添加数据
# 首先是创建主表的一份数据
userObj = User(
    user_name='Rose' + str(datetime.now()),
    password='123456',
    real_name='肉丝',
    sex=2
)
# 一个人可以对应多个地址
userObj.address.append(
    UserAddress(user=userObj, area="地址01", phone_num="11111111111")
)
userObj.address.append(
    UserAddress(user=userObj, area="地址02", phone_num="11111111111")
)
session.add(userObj)  # 添加这个人的时候同时会添加2份数据
profile = UserProfile(user=userObj, hobby='宝石')  # 一对一的详细信息
session.add(profile)
session.commit()  # 在提交之前会自动进行回滚  如果使用 session.begin() session.rollback()
session.close()

索引/基础/条件查询

# 根据用户ID查询信息(根据主键进行查询)
idIndex = 1
session = Session(bind=engine, future=True)
userObj = session.get(User, idIndex)  # 根据主键进行查询
userObjDetail = '{} => {}'.format(userObj.user_name, userObj.real_name)
# 使用select查询全部/第一个
stmt = select(User)
rows = session.execute(stmt)  # 要全部
maps = session.execute(stmt).mappings()  # 返回的是字典
rowOnlySome = session.execute(select(User.id, User.user_name))  # 只要指定的几个字段
rowOne = session.execute(stmt).fetchone()  # 只要第一个
rowStillOne = session.execute(stmt).scalars().first()  # 只要第一个且为ORM的实体对象

# 使用SQLAlchemy进行条件查询
# 使用where条件查询
# User.id > 12
# User.id.between(8,12)
# User.id.is_(None)
# User.id.is_not(None)
# User.id.in_((9, 12))
# or_(User.id == 9, User.id == 12)
# User.id.like("Hello%")
# User.id.like("Hello_")
# where(xxxx).where(xxxx)可以连续或者and_(User.id == 9, User.password == 123456)
# or_(and_(User.id == 9, User.password == 123456), and_(User.id == 9, User.password == 123456)) # 并集
stmt = select(User).where(User.id == 1)
rowWhere = session.execute(stmt).scalar_one_or_none()  # 没有就返回None

函数/多表/分组/去重/排序/分页

  • func.count()类型的
  • query(User).count()类型的
# 函数的使用
stmt = select(func.count().label("total")).select_from(User)
row = session.execute(stmt).mappings().one()  # 字典的形式访问
total = session.query(User).filter(User.id > 10).count()  # 使用query
stmt = select(func.max(User.id).label("max_id"), func.min(User.id).label("min_id")).where(User.password == 123456)
maxAndMin = session.execute(stmt).mappings().one()

# 多表查询
# 由上取下面的数据
user = session.get(User, 24)
addList = user.address
areas = [each.area for each in addList]
# 由下面取上面的数据
address = session.get(UserAddress, 23)
userInfo = address.user
# 因为开启了lazy可以进一步筛选
newAddList = addList.filter(UserAddress.id > 1)

# 分组与去重
# having()是一样的
stmt = select(User.password).distinct()
res = session.execute(stmt).scalars().all()
stmt = select(User.sex, func.count().label("total")).group_by(User.sex)
resTotal = session.execute(stmt).mappings().all()

# 排序与分页
# order_by(xxxx.desc()) # 倒序
# order_by(desc(label)) # 如果有新创建标签则可以这样
# offset()是偏移量的意思
# limit()是限制多少的意思
# 两者联合使用就可以产生分页的效果
# 注意: 从11-20则偏移量为10

更改/删除

# 修改数据
# 修改单条信息
# 拿到对应的-》修改属性-》添加进入-》提交事务
oneObj = session.get(User, 10)
oneObj.password = 123789
session.add(oneObj)
session.commit()
# 批量修改
# stmt = update(User).where(User.id < 10).values(password=User.password + 1)
stmt = update(User).where(User.id < 10).values(password=User.password + 1).execution_options(
    synchronize_session="fetch")  # 修改同步策略
resInfo = session.execute(stmt)  # 执行
session.commit()  # 提交
print(resInfo.rowcount)  # 查看受影响的行数
# 删除数据
# 删除单条数据
# 拿到对应-》删除-》提交
oneObj = session.get(User, 11)
session.delete(oneObj)
session.commit()
# 连着关联信息删除
# 对应的Column上要改 relation上也要改
# 多时用的是软删除
# 批量删除
# 删除时候指定条件-》执行-》提交
stmt = delete(User).where(User.id > 100)
resInfo = session.execute(stmt)
session.commit()
print(resInfo.rowcount)  # 查看受影响的行数

你可能感兴趣的:(开发,mysql,python,数据库)