Python与数据库的新人手册 -- MySQL

栏目: Python · 发布时间: 5年前

内容简介:Python支持的数据库有很多,本文将主要拿首先安装基本的数据库驱动

Python支持的数据库有很多, MySQL 作为主流数据库之一,我们不妨了解下它们之间的 小故事 Python操作 MySQL 的库有三个, python-MySQL(MySQLdb)PyMySQLSQLAlchemy

python-MySQL(MySQLdb)
PyMySQL
SQLAlchemy

本文将主要拿 SQLAlchemy 来进行了解学习。

安装工具

首先安装基本的数据库驱动 pymysql

pip3 install pymysql
复制代码

然后安装ORM框架 SQLAlchemy

pip3 install sqlalchemy
复制代码

日常工作中,如果不想每次通过命令行来查看数据的话。推荐安装 Navicat for MySQL ,通过这个图形化 工具 能够方便快捷地操作数据库,实时查询数据。

Python与数据库的新人手册 -- MySQL

初始化数据库

安装好必要工具后,我们开始尝试创建个用户数据 user 表来。 首先,使用 SQLAlchemy 连接数据库并定义表结构初始化DBSession。

# 导入SQLAlchemy
from sqlalchemy import Column, BIGINT, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 创建基类
Base = declarative_base()

# 初始化数据库连接:
# '数据库类型+数据库驱动名称://用户名:密码@数据库地址:端口号/数据库名'
engine = create_engine('mysql+pymysql://root:123123@mysql:3306/test')

# 创建DBSession类型:
DBSession = sessionmaker(bind=engine)
# 创建session对象:
session = DBSession()

# 数据库操作方法
# 初始化数据库
def init_db():
    Base.metadata.create_all(engine)
# 删除数据库
def drop_db():
    Base.metadata.drop_all(engine)
复制代码

建立 user 数据表模型:

# 定义user类
class User(Base):
    # 表名
    __tablename__ = "user"

    # 表的结构
    # 设置id为主键 并自增长
    id = Column(BIGINT, primary_key=True, autoincrement=True)
    name = Column(String(20))
    gender = Column(String(2))

# 正式初始化数据库,如果没有user表的话,这里将自动创建
init_db()
复制代码

这里有个需要注意的地方就是在初始化数据库之前需要先定义 user 数据表模型,否则的话无法正常创建 user 数据表。 session (会话),可以看成一个管理数据库持久连接的对象,后面的操作都将基于 session 对象进行。

如果使用INT自增类型,那么当一张表的记录数超过2147483647(约21亿)时,会达到上限而出错。使用BIGINT自增类型则可以最多约922亿亿条记录。

增删改查操作

初始化ORM对象后,我们插入一条记录试试。

# 创建新User对象:
new_user = User(name='mrlizi', gender='man')
# 添加到session:
session.add(new_user)
# 批量添加
session.add_all([
    User(name='子非鱼', gender='M'),
    User(name='虞姬', gender='F'),
    User(name='花木兰', gender='F')
])
# 提交即保存到数据库:
session.commit()
复制代码

结果:

Python与数据库的新人手册 -- MySQL

Sessionquery 函数会返回一个Query对象。query函数可以接受多种参数类型。

# query: 输出所有的用户名
result = session.query(User.name)
# order: 按倒序输出所有用户
result = session.query(User).order_by(User.id.desc())
result = session.query(User).order_by(-User.id)
# label: 自定义字段名,查询结果可通过item.my_name来获取用户名
for item in session.query(User.name.label('my_name')).all()
# filter和filter_by: 筛选用户名为'mrlizi'的用户
result = session.query(User).filter(User.name=='mrlizi').one()
result = session.query(User).filter_by(name='mrlizi').one()
# offset和limit:组合起来可做分页查询(通过 python 的切片其实也一样),下面的两种语句的查询结果是相同的
result = session.query(User).offset(2).limit(1).all()
result = session.query(User)[1:3]

# AND: 与查询      
result = session.query(User).filter(and_(User.name=='mrlizi', User.gender=='M')).all()
result = session.query(User).filter(User.name=='mrlizi', User.gender=='M')
result = session.query(User).filter(User.name=='mrlizi').filter(User.gender=='M').all()
# OR: 或查询
result = session.query(User).filter(or_(User.name == '子非鱼', User.name == '花木兰'))
# 模糊查询
result = session.query(User).filter(User.name.like('子%')).all()
复制代码

基本日常用到的查询方法就是这些,面向对象操作的用法都比较灵活多变,大家可以根据不同才场景自由组合。

相比去查询来讲,修改就显得简单很多,找到命中的记录,然后通过 update 方法来进行修改。 update 方法的 synchronize_session 参数用于在更新数据后是否对当前的session进行更新, synchronize_session = False 不同步更新当前session synchronize_session = 'fetch' 更新之前从数据库中拉取实时数据,更新到session对象 synchronize_session = 'evaluate' 更新之前先记录符合的对象,更新完后对记录的对象进行删除。(意思是不与数据库进行同步更新,仅更新当前的session记录)

# 方法一
session.query(User).filter(User.name == 'mrlizi').update({'name': '李白'})
# 方法二
user = session.query(User).filter(User.name == '李白').first()
user.name = '铠'
# 操作方式
result = session.query(User).filter(User.name == '虞姬').update({User.name: '孙尚香'}, synchronize_session='fetch')
# 提交
session.commit()
复制代码

删除的话,无非就是 查询 到目标记录,然后进行删除。

# 使用查询语句,filter是where条件,最后调用delete()进行删除记录:
session.query(User).filter_by(name="铠").delete()
session.commit()
复制代码

关联表查询

MySQL 作为关系型数据库,可以通过设置外键来进行多个表互相关联查询。相应的, SQLAlchemy 也提供了对象之间的一对一、一对多、多对多关联功能。

一对多

SQLAlchemy 的一对多关系中,使用 ForeignKey() 来表示表的外键, relationship() 表示表与表之间关联的属性。

def one_to_many():
    # 定义user类
    class User(Base):
        # 表名
        __tablename__ = "user"

        # 表的结构
        # 设置id为主键 并自增长
        id = Column(BIGINT, primary_key=True, autoincrement=True)
        name = Column(String(20))
        # 定义用户关注的公众号属性,指明两者的关系
        account = relationship('Account', back_populates="user")

    class Account(Base):
        __tablename__ = 'account'

        id = Column(BIGINT, primary_key=True, autoincrement=True)
        name = Column(String(20))
        # 设置外键关联到user表的:
        user_id = Column(BIGINT, ForeignKey('user.id'))
        # 定义 Account 的 user 属性,指明两者关系
        user = relationship("User", back_populates="account")

    # 清空数据库并重新初始化
    drop_db()
    init_db()

    mrlizi = User(name='mrlizi')
    mrlizi.account = [
        Account(name='攻城狮峡谷'),
        Account(name='zone7')
    ]
    session.add(mrlizi)

    result = session.query(User).filter(User.name == 'mrlizi').one()
    for item in result.account:
        print(item.name)

    result = session.query(Account).filter(Account.name == '攻城狮峡谷').one()
    print(result.user.name)

    session.commit()

one_to_many()
复制代码

上面代码的实现过程:

user
user
account

一对一

一对一其实就是两个表互相关联,我们只需要在 一对多 关系基础上的父表中使用 uselist 参数来表示。实现代码如下:

def one_to_one():
    # 定义user类
    class User(Base):
        __tablename__ = "user"

        id = Column(BIGINT, primary_key=True, autoincrement=True)
        name = Column(String(20))
        account = relationship('Account', uselist=False, back_populates="user")

    # 公众号类
    class Account(Base):
        __tablename__ = 'account'

        id = Column(BIGINT, primary_key=True, autoincrement=True)
        name = Column(String(20))
        # 设置外键关联到user表的:
        user_id = Column(BIGINT, ForeignKey('user.id'))
        # 定义 Account 的 user 属性,指明两者关系
        user = relationship("User", back_populates="account")

    # 清空数据库并重新初始化
    drop_db()
    init_db()

    # 添加记录
    user = User(name='子非鱼')
    user.account = Account(name='攻城狮峡谷')
    session.add(user)
    session.commit()

    # 查询
    result = session.query(User).filter(User.name == '子非鱼').one()
    print(result.account.name)
    # 输出:
    # 攻城狮峡谷

one_to_one()
复制代码

多对多

多对多是通过两个表之间增加一个关联的表来实现,这个关联表使用 MetaData 对象来与两个表关联,并用 ForeignKey 参数指定链接来定位到两个不同的表,两个不同的表则在 relationship() 方法中通过 secondary 参数来指定关联表。

def many_to_many():
    # 关联表
    association_table = Table('association', Base.metadata,
                              Column('user_id', BIGINT, ForeignKey('user.id')),
                              Column('account_id', BIGINT, ForeignKey('account.id'))
                              )

    class User(Base):
        __tablename__ = "user"

        id = Column(BIGINT, primary_key=True, autoincrement=True)
        name = Column(String(20))
        accounts = relationship('Account', secondary=association_table, back_populates="users")

    class Account(Base):
        __tablename__ = 'account'

        id = Column(BIGINT, primary_key=True, autoincrement=True)
        name = Column(String(20))
        users = relationship("User", secondary=association_table, back_populates="accounts")

    # 清空数据库并重新初始化
    drop_db()
    init_db()
    
    # 创建记录
    user1 = User(name='子非鱼')
    user2 = User(name='zone')
    user3 = User(name='mrlizi')
    account1 = Account(name='攻城狮峡谷')
    account2 = Account(name='zone7')

    # 关联记录
    user1.accounts = [account1]
    user2.accounts = [account1, account2]
    user3.accounts = [account2]

    # 添加并保存
    session.add(user1)
    session.add(user2)
    session.add(user3)
    session.commit()

    # 双向查询
    result1 = session.query(User).filter(User.name == 'zone').one()
    for item in result1.accounts:
        print(item.name)
    result2 = session.query(Account).filter(Account.name == '攻城狮峡谷').one()
    for item in result2.users:
        print(item.name)

many_to_many()
复制代码

总结

MySQL作为主流的数据库之一,我们不一定说要多深入去研究它的使用,但起码的了解还是要有的。而且python中使用MySQL还是挺简单的,代码敲着敲着就会了。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective Modern C++ 简体中文版

Effective Modern C++ 简体中文版

Scott Meyers / 高博 / 中国电力出版社 / 2018-4-23 / 99

想要彻底理解C++11和C++14,不可止步于熟悉它们引入的语言特性(例如,auto型别推导、移动语义、lambda表达式以及并发支持)。挑战在于高效地运用这些特性——从而使你的软件具备正确性、高效率、可维护性和可移植性。这正是这本实用的图书意欲达成的定位。它描述的正是使用C++11和C++14——现代C++来撰写真正卓越的软件之道。 涵盖以下主题: 大括号初始化、noexcept规格......一起来看看 《Effective Modern C++ 简体中文版》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具