本节课程是关于 MySQL (数据库)和 SQLAlchemy(python中最流行ORM) 的应用学习。
1.MySQL(关系型数据库) MySQL本质上是一个关系连结的多表组合,本表的外键对应的是它表的主键(例如学生信息表中的指导老师[外键]和老师信息表中的任职老师[主键]),启动MySQL的命令是—— sudo service mysql start 接着构建 python 与 MySQL 之间的连接 sudo pip3 install mysqlclient
MySQL 数据库由服务器端和客户端组成,通过在客户端 mysqlclient 输入:
mysql -u root #以 root 超级管理员身份登陆服务器,效果如下
1.1基本操作 CREATA DATABASE/TABLE database_name/table_name #创建数据库/表,但表的创建必须同时设定字段名称和数据类型,例如—— CREATE TABLE user ( 列名 数据类型(数据长度) )
INSERT INTO table_name VALUES(val1, val2, val3) #对指定表插入值,可以列出字段名称,也可以按默认顺序插入。
DROP DATABASE/TABLE database_name/table_name #丢弃指定数据库/表 describe table_name #显示表的全部字段信息。
select * from table_name #显示表中数据,下图是 describe 和select*from的效果差异——
对表中字段的数据要设置去重约束,可以通过以下两种方式任一实现: alter table user modify 字段名 varchar(64) unique; #修改某字段添加唯一索引 alter table user add constraint unique (字段名); #对某字段设置唯一索引
在设置跨表约束时(如外键约束),需同时满足它表主键和本表外键已经设置的条件,效果是插入值在它表不存在时无法完成本表插入,删除本表时若可能破坏waijia你,则本表删除失败等。
PS:通过auto_increment指定字段id为自增模式,当插入新值时不需要给定该字段值,它会随插入自增。
练习题1:创建问答表
create table question (
id int(10) auto_increment,
name varchar(64) not null,
content varchar(64),
course_id int(10) not null,
primary key (id),
constraint fk_course foreign key (course_id) references course(id)
);
运行效果
2.SQLAlchemy SQLAlchemy 是 Python 语言中一个功能强大的 ORM (对象关系映射Object Relational Mapping) 包,有了它就不必通过 sql 语句访问数据库,而是把 Python 对象映射到数据库中去。
2.1 virtualenv virtualenv 是一个隔离的虚拟环境,常用于搭配 ipython 和 sqlalchemy 组合使用,需要注意的是,每当在 virtualenv 中安装了软件包,需要输入 deactivate 退出虚拟环境,再输入 source env/bin/activate 进入 virtualenv 才可使用该软件。
使用 SQLAlchemy 连接数据库主要通过 Engine 进行,先从 sqlalchemy 引入 create_engine 类,然后创建一个 engine 的简单示例:
create_engine('mysql://:@/') #传入数据库的访问地址
engine.execute('sql') #执行一条 sql 命令语句
2.2 映射类的创建和访问操作
若是想让 Python 类映射到数据库,需要使用到声明基类-创建类,意指在声明基类上创建 Python 类,可以让类直接映射到数据库对应的表上。
创建声明基类,首先需要从 sqlalchemy 中引入 declarative_base,再定义 declarative_base 以备后续使用。
再创建 Python 类,映射数据库中的指定表。
PS:输入 Python 类.table 可以显示该类的属性。
想通过 Python 类访问数据库的话,需要引入 Session ,它是映射类与数据库沟通的桥梁,从 sqlalchemy 导入后,调用 Session() ,使用 session.query(映射类名) 实现查询/字段过滤查询。
PS:上图中,使用 filter 能够实现对数据进行筛选的作用。filter 中的运算符可以填入 SQL WHERE 子句中的运算符(像 ==, !=, >, < 等),或者是 AND, OR 等运算符。另外,这里的 filter 也可以更换为 filter_by 函数。
2.3 基于映射类生成数据库表
class Lab(Base): ...: tablename = 'lab' #定义表名 ...: id = Column(Integer, primary_key=True) #整数型,主键设置 ...: name = Column(String(64)) ...: course_id = Column(Integer, ForeignKey('course.id')) #外键设置 ...: course = relationship('Course', backref='labs') #从Course实例上,通过 course.labs 访问对应关联的 labs 值。 ...: def repr(self): ...: return '<Lab(name=%s)>' % self.name
生成命令 Base.metadata.create_all(engine)
运行效果( MySQL 中查看)
练习题2
In [42]: class Path(Base):
...: tablename = 'path'
...: id = Column(Integer, autoincrement=True, primary_key=True)
...: name = Column(String(64), nullable=False)
...: config = Column(String(128))
...: def repr(self):
...: return '<Path(name=%s)>' % self.name
...:
In [43]: Base.metadata.create_all(engine)
运行效果( MySQL 中查看)
2.4 CRUD操作
course = session.query(Course).first() #查询出需要管理的课程对象
lab1 = Lab(name='ORM base', course_id=course.id)
lab2 = Lab(name='MySQL', course=course) #创建两个实验
session.add(lab1)
session.add(lab2) #将数据变更提交到数据库中前,需要将数据通过session.add 方法添加到 session 中
session.commit() #通过 session.commit() 操作提交到了数据库中
In [26]: course.labs
Out[26]: [<Lab(name=MySQL)>, <Lab(name=ORM base)>]
PS:创建实验时,关联到课程有两种办法,一种是直接赋值给 course_id , 另外一种办法是赋值给定义的关系属性 course 。当数据成功插入数据库后,就可以通过 course.labs 获取这两个实验。
运行效果
需要更新数据库的字段信息时,通过更新对象的属性即可实现,例如:
需要删除数据的时候,通过 session.delete 删除指定对象即可
练习题3
In [44]: path = session.query(Path).first()
In [45]: path1 = Path(name='Python', config='{'description':'Python path'}')
In [46]: path2 = Path(name='BigData', config='{'description':'BigData path'}')
In [47]: session.add(path1)
In [48]: session.add(path2)
In [49]: session.commit()
In [50]: session.query(Path).all()
Out[50]: [<Path(name=Python)>, <Path(name=BigData)>]
运行效果
2.5 1:1 与 M:M 1:1 意指两张表之间的数据项是一对一的关系(一个用户对应一个身份证号码),1:M 意指一对多的关系(一个课程对应多个实验), M:M 意指多对多的关系(一个短视频有多个标签,一个标签关联多个短视频)。
1:1 构建上很简单,本表的主键+外键都在同一个字段,且关联它表的主键。 In [86]: class UserInfo(Base): ...: tablename = 'userinfo' ...: user_id = Column(Integer, ForeignKey('user.id'), primary_key=True) ...: addr = Column(String(512)) ...: In [87]: Base.metadata.create_all(engine)
M:M 构建可以利用中间表(对两边表都是 1:M 的关系)实现,例如: In [14]: class Course(Base): ...: tablename = 'course' ...: id = Column(Integer, primary_key=True) ...: name = Column(String(50)) ...: teacher_id = Column(Integer, ForeignKey('user.id')) ...: teacher = relationship('User') ...: def repr(self): ...: return '<Course(name=%s)>' % self.name ...:
In [15]: from sqlalchemy import Table, Text
In [16]: course_tag = Table('course_tag', Base.metadata, ...: Column('course_id', ForeignKey('course.id'), primary_key=True), ...: Column('tag_id', ForeignKey('tag.id'), primary_key=True) ...: )
In [17]: class Tag(Base): ...: tablename = 'tag' ...: id = Column(Integer, primary_key=True) ...: name = Column(String(64)) ...: courses = relationship('Course', ...: secondary=course_tag, ...: backref='tags') ...: def repr(self): ...: return '<Tag(name=%s)>' % self.name ...: #可以看到上述 Course,Tag 表和 course_tag 表都是 1:M 的关系,通过 course_tag 这张中间表成功的建立了 M:M 的关系
In [18]: Base.metadata.create_all(engine) 值得注意的是,Tag 表中定义了 courses 属性,该属性通过 relationship 函数的 secondary 参数告诉 SQLAlchemy 通过表 course_tag 关联到 Course 表的对象上。
以下为多对多的 CRUD 操作
就像操作 Python 列表一样,通过 course.tags.append(tag1) 向课程中添加标签,结尾基于 engine.execute 执行 SQL 查询验证了标签确实插入了数据库中,而且 course_tag 表中也生成了相应的关系记录。
以下尝试向 course 表中创建一门课程,并添加到 tag1 标签中.
学习时间 475分钟
操作时间 351分钟
按键次数 19881次
实验次数 10次
报告字数 7698字
是否完成 完成