文章目录
1. SQLALchemy 连接数据库
-
SQLAlchemy介绍和基本使用:
-
数据库是一个网站的基础。Flask可以使用很多种数据库。比如MySQL,MongoDB,SQLite,PostgreSQL等。这里我们以MySQL为例进行讲解。而在Flask中,如果想要操作数据库,我们可以使用ORM来操作数据库,使用ORM操作数据库将变得非常简单。我们会以 mysql + SQLAlchemy 组合进行讲解。
-
在讲解Flask中的数据库操作之前,先确保你已经安装了以下软件:
-
mysql:如果是在windows上,到官网下载。如果是ubuntu,通过命令sudo apt-get install mysql-server libmysqlclient-dev -yq进行下载安装。
-
MySQLdb:MySQLdb是用Python来操作mysql的包,因此通过pip来安装,命令如下:pip install mysql-python。如果您用的是Python 2.x,请安装MySQLdb。
-
pymysql:pymysql是用Python来操作mysql的包,因此通过pip来安装,命令如下:pip3 install pymysql。如果您用的是Python 3,请安装pymysql。
-
SQLAlchemy:SQLAlchemy是一个数据库的ORM框架,我们在后面会用到。安装命令为:pip3 install SQLAlchemy。
-
-
通过SQLAlchemy连接数据库
- 首先来看一段代码:
from sqlalchemy import create_engine # 数据库的配置变量
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'xt_flask'
USERNAME = 'root'
PASSWORD = 'root'
DB_URI = 'mysql+mysqldb://{}:{}@{}:{}/{}'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE) # 创建数据库引擎 engine = create_engine(DB_URI) #创建连接
with engine.connect() as con:
rs = con.execute('SELECT 1')
print rs.fetchone()
-
首先从sqlalchemy中导入create_engine,用这个函数来创建引擎,然后用engine.connect()来连接数据库。其中一个比较重要的一点是,通过create_engine函数的时候,需要传递一个满足某种格式的字符串,对这个字符串的格式来进行解释:
dialect+driver://username:password@host:port/database?charset=utf8
-
dialect是数据库的实现,比如MySQL、PostgreSQL、SQLite,并且转换成小写。driver是Python对应的驱动,如果不指定,会选择默认的驱动,比如MySQL的默认驱动是MySQLdb。
username
是连接数据库的用户名,password
是连接数据库的密码,host
是连接数据库的域名,port
是数据库监听的端口号,database
是连接哪个数据库的名字。如果以上输出了1,说明SQLAlchemy能成功连接到数据库。
- 用SQLAlchemy执行原生SQL(扩展):
- 我们将上一个例子中的数据库配置选项单独放在一个 constants.py 的文件中,看以下例子:
from sqlalchemy import create_engine from constants import DB_URI
# 连接数据库
engine = create_engine(DB_URI,echo=True)
# 使用with语句连接数据库,如果发生异常会被捕获
with engine.connect() as con:
# 先删除users表
con.execute('drop table if exists authors')
# 创建一个users表,有自增长的id和name
con.execute('create table authors(id int primary key auto_increment,'name varchar(25))')
# 插入两条数据到表中
con.execute('insert into persons(name) values("abc")')
con.execute('insert into persons(name) values("xiaotuo")')
# 执行查询操作
results = con.execute('select * from persons')
# 从查找的结果中遍历
for result in results:
print(result)
- 必须掌握:
from sqlalchemy import create_engine
#准备连接数据库基本信息
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'first_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root'
# dialect+driver://username:password@host:port/database?charset=utf8
# 按照上述的格式来 组织数据库信息
DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
# 创建数据库引擎
engine = create_engine(DB_URI)
# 创建连接
conn = engine.connect()
# 判断是否连接成功
result =conn.execute('select 1')
print(result)
print(result.fetchone())
2. ORM 介绍
-
ORM:Object Relationship Mapping
-
大白话:对象模型与数据库表的映射
-
python 代码和 SQL 代码角度理解:
class Person(object):
name = 'xx'
age = 18
country ='xx'
# Person类 -> 数据库中的一张表
# Person类中的属性 -> 数据库中一张表字段
# Person类的一个对象 -> 数据库中表的一条数据
# p = Person('xx',xx)
# p.save()
# create table person(name varchar(200),age int,country varchar(100))
-
SQLAlchemy:随着项目的越来越大,采用写原生SQL的方式在代码中会出现大量重复的SQL语句,那么,问题,就出现了:
- SQL语句重复利用率不高,越复杂的SQL语句条件越多,代码越长,会出现很多相近的SQL语句。
- 很多SQL语句 是在业务逻辑中拼接出来的,如果数据库需要更改,就要去修改这些逻辑,这会很容易漏掉对某些SQL语句的修改。
- 写SQL时容易忽略web安全问题(SQL注入问题),造成隐患。
-
ORM,全称Object Relational Mapping,中文名叫做对象关系映射,通过ORM我们可以通过类的方式去操作数据库而不用再写原生的SQL语句,通过把表映射成类,把行作为实例,把字段作为属性,ORM在执行对象操作的时候最终还是会把对象的操作转换为数据库的原生语句,但使用ORM有许多优点:
- 易用性:使用ORM做数据库开发可以有效减少重复SQL语句的概率,写出来的模型也更加直观、清晰
- 性能损耗小:ORM转换成底层数据库操作指令确实会有一些开销。但是从实际情况来看,这种性能损耗很少(不足5%),只要不是针对性能有严苛的要求,综合考虑开发效率、代码阅读性,带来的好处远大于性能损耗,而且项目越大作用越明显。
- 设计灵活:可以轻松的写出复杂的查询。
- 可移植性:SQLAlchemy封装了底层的数据库实现,支持多个关系数据库引擎,包括流行的Mysql、PostgreSQL和SQLite,可以非常轻松的切换数据库。
-
示例:
from sqlalchemy import create_engine
# 准备连接数据库基本信息
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'first_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root'
# dialect+driver://username:password@host:port/database?charset=utf8
# 按照上述的格式来 组织数据库信息
DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
# 创建数据库引擎
engine = create_engine(DB_URI)
# 创建连接
conn = engine.connect()
# 判断是否连接成功
result =conn.execute('select 1')
print(result)
print(result.fetchone())
3. 定义 ORM 模型并将其映射到数据库中
步骤:
- 用
declarative_base
根据engine
创建一个ORM基类。
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine(DB_URI)
Base = declarative_base(engine)
- 用这个
Base
类作为基类来写自己的ORM类。要定义__tablename__
类属性,来指定这个模型映射到数据库中的表名。
class Person(Base):
__tablename__ ='person'
- 创建属性来映射到表中的字段,所有需要映射到表中的属性都应该为
Column
类型:
class Person(Base):
__tablename__ ='person'
# 2.在这个ORM模型中创建一些属性,来跟表中的字段进行 一一 映射。这些属性必须是sqlalchemy给我们提供好的数据类型
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(50))
age = Column(Integer)
country = Column(String(50))
- 使用
Base.metadata.create_all()
来将模型映射到数据库中。
Base.metadata.create_all()
- 一旦使用
Base.metadata.create_all()
将模型映射到数据库中后,即使改变了模型的字段,也不会重新映射了。
- 示例:
from sqlalchemy import create_engine,Column,Integer,String
from sqlalchemy.ext.declarative import declarative_base
# 准备连接数据库基本信息
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'first_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root'
# dialect+driver://username:password@host:port/database?charset=utf8
# 按照上述的格式来 组织数据库信息
DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
# 创建数据库引擎
engine = create_engine(DB_URI)
# 需求:创建好一个ORM类模型 并映射到指定的数据库中成为 表
# 01. 用`declarative_base`根据`engine`创建一个ORM基类。
Base = declarative_base(engine)
class Person(Base):
# 02. 用这个`Base`类作为基类来写自己的ORM类。要定义`__tablename__`类属性,来指定这个模型映射到数据库中的表名。
__tablename__ = "t_person"
# 03.在这个ORM模型中创建一些属性,来跟表中的字段进行 一一 映射。这些属性必须是sqlalchemy给我们提供好的数据类型
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(50),nullable=False)
age = Column(Integer)
country = Column(String(50))
nick =Column(String(20))
# 04. 使用`Base.metadata.create_all()`来将模型映射到数据库中。
# Base.metadata.create_all()
#注意点: 一旦使用`Base.metadata.create_all()`将模型映射到数据库中后,即使改变了模型的字段,也不会重新映射了。
Base.metadata.drop_all() #将Base上的ORM类模型对应数据中的表都删除
Base.metadata.create_all() #创建Base上的ORM类到数据库中成为表
4. SQLAlchemy 对数据的增删改查操作 (“CRUD”操作)
用session做数据的增删改查操作:
- 构建session对象:所有和数据库的ORM操作都必须通过一个叫做
session
的会话对象来实现,通过以下代码来获取会话对象:
from sqlalchemy.orm import sessionmaker
engine = create_engine(DB_URI)
Base = declarative_base(engine)
session = sessionmaker(engine)()
- 添加对象:
- 创建对象,也即创建一条数据:
p1 = Person(name='momo1',age=19,country='china')将
- 这个对象添加到
session
会话对象中:
session.add(p1)
- 将session中的对象做
commit
操作(提交):
session.commit()
- 一次性添加多条数据:
p1 = Person(name='momo1',age=19,country='china')
p2 = Person(name='momo2',age=20,country='china')
session.add_all([p1,p2])
session.commit()
- 查找对象:
# 查找某个模型对应的那个表中所有的数据:
all_person = session.query(Person).all()
# 使用filter_by来做条件查询
all_person = session.query(Person).filter_by(name='momo1').all()
# 使用filter来做条件查询
all_person = session.query(Person).filter(Person.name=='momo1').all()
# 使用get方法查找数据,get方法是根据id来查找的,只会返回一条数据或者None
person = session.query(Person).get(primary_key)
# 使用first方法获取结果集中的第一条数据
person = session.query(Person).first()
- 修改对象:首先从数据库中查找对象,然后将这条数据修改为你想要的数据,最后做commit操作就可以修改数据了。
person = session.query(Person).first()
person.name = 'lulu'
session.commit()
- 删除对象:将需要删除的数据从数据库中查找出来,然后使用
session.delete
方法将这条数据从session中删除,最后做commit操作就可以了。
person = session.query(Person).first()
session.delete(person)
session.commit()
- 示例:
from sqlalchemy import create_engine,Column,Integer,String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
# 准备连接数据库基本信息
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'first_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root'
# ialect+driver://username:password@host:port/database?charset=utf8
# 按照上述的格式来 组织数据库信息
DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
# 创建数据库引擎
engine = create_engine(DB_URI)
# 需求:创建好一个ORM类模型;并映射到指定的数据库中成为 表
# 01. 用`declarative_base`根据`engine`创建一个ORM基类。
Base = declarative_base(engine)
class Person(Base):
# 02. 用这个`Base`类作为基类来写自己的ORM类。要定义`__tablename__`类属性,来指定这个模型映射到数据库中的表名。
__tablename__ = "t_person"
# 03.在这个ORM模型中创建一些属性,来跟表中的字段进行 一一 映射。这些属性必须是sqlalchemy给我们提供好的数据类型
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(50),nullable=False)
age = Column(Integer)
country = Column(String(50))
nick =Column(String(20))
def __repr__(self):
return "<name:{0},age:{1}>".format(self.name,self.age)
# 04. 使用`Base.metadata.create_all()`来将模型映射到数据库中。
# Base.metadata.create_all()
# 注意点: 一旦使用`Base.metadata.create_all()`将模型映射到数据库中后,即使改变了模型的字段,也不会重新映射了。
# Base.metadata.drop_all() #将Base上的ORM类模型对应数据中的表都删除
# Base.metadata.create_all() #创建Base上的ORM类到数据库中成为表
# 需求:CRUD的操作
# 前提:获取到跟数据库进行会话的对象
# Session = sessionmaker(engine)
# session = Session()
session = sessionmaker(engine)()
# 01.对表 添加数据
# 一次只能插入【一条数据】
# p = Person(name="momo",age=18,country="china",nick="莫莫")
# session.add(p)
# session.commit()
# 一次能插入【多条数据】
# p2 = Person(name="lulu",age=20,country="china",nick="露露")
# p3 = Person(name="tantan",age=20,country="china",nick="探探")
# session.add_all([p2,p3])
# session.commit()
# 02.查询 表数据
# 2.1 全表查询
# ps = session.query(Person).all()
# for p in ps:
# print(p)
# 2.2 条件查询:filter_by
# ps = session.query(Person).filter_by(name="momo").all()
# for p in ps:
# print(p)
# 2.3 条件查询:filter
# ps = session.query(Person).filter(Person.name=="momo").all()
# for p in ps:
# print(p)
# 2.4 条件查询:get
# p = session.query(Person).get(2)
# print(p)
# 2.5 条件查询:first
# p = session.query(Person).first()
# print(p)
# 03.修改表,指定行数据
# person = session.query(Person).first()
# print(person)
# person.name ="haha"
# session.commit()
# 04.删除表数据
person = session.query(Person).get(3)
print(person)
session.delete(person)
session.commit()
5. SQLAlchemy 常用数据类型
-
Integer:整形,映射到数据库中是int类型。
-
Float:浮点类型,映射到数据库中是float类型。他占据的32位。
-
Double:双精度浮点类型,映射到数据库中是double类型,占据64位 (SQLALCHEMY中没有)。
-
String:可变字符类型,能存储六千多个字符;映射到数据库中是varchar类型。
-
Boolean:布尔类型,映射到数据库中的是tinyint类型。
-
DECIMAL:定点类型。是专门为了解决浮点类型精度丢失的问题的。在存储钱相关的字段的时候建议大家都使用这个数据类型。并且这个类型使用的时候需要传递两个参数,第一个参数是用来标记这个字段总能能存储多少个数字,第二个参数表示小数点后有多少位。
-
Enum:枚举类型。指定某个字段只能是枚举中指定的几个值,不能为其他值。在ORM模型中,使用Enum来作为枚举,示例代码如下:
- 方式01:(简单易读;但容易出错)
class News(Base):
__tablename__ = 'news'
tag = Column(Enum("python",'flask','django'))
在Python3中,已经内置了enum这个枚举的模块,我们也可以使用这个模块去定义相关的字段。示例代码如下:
- 方式02:(麻烦;但不易出错)
import enum
class TagEnum(enum.Enum):
python = "python"
flask = "flask"
django = "django"
class News(Base):
__tablename__ = 'news'
id = Column(Integer,primary_key=True,autoincrement=True)
tag = Column(Enum(TagEnum))
news = News(tag=TagEnum.flask)
-
Date:存储时间,只能存储年月日。映射到数据库中是date类型。在Python代码中,可以使用
datetime.date
来指定。 -
DateTime:存储时间,可以存储年月日时分秒毫秒等。映射到数据库中也是datetime类型。在Python代码中,可以使用
datetime.datetime
来指定。 -
Time:存储时间,可以存储时分秒。映射到数据库中也是time类型。在Python代码中,可以使用
datetime.time
来至此那个。示例代码如下:
class News(Base):
__tablename__ = 'news'
create_time = Column(Time)
news = News(create_time=time(hour=11,minute=11,second=11))
-
Text:存储长字符串。一般可以存储6W多个字符。如果超出了这个范围,可以使用LONGTEXT类型。映射到数据库中就是text类型。
-
LONGTEXT:长文本类型,映射到数据库中是longtext类型。
- 演示示例:
from sqlalchemy import create_engine,Column,Integer,String,Float,DECIMAL,Boolean,Enum,Date,DateTime,Time,Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import sessionmaker
from datetime import date,datetime,time
# 在python3.x中,有enum模块
import enum
# 准备连接数据库基本信息
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'first_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root'
# dialect+driver://username:password@host:port/database?charset=utf8
# 按照上述的格式来 组织数据库信息
DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
# 创建数据库引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)
# 需求:sqlalchemy中常用的字段数据类型有哪些?
# 定义一个枚举类
class TagEnum(enum.Enum):
python="Python"
flask="FLASK"
django="DJANGO"
class News(Base):
__tablename__='news'
id = Column(Integer,primary_key=True,autoincrement=True)
price1 = Column(Float) #存储数据时存在精度丢失问题
price2 = Column(DECIMAL(10,4))
title = Column(String(50))
is_delete =Column(Boolean)
tag1 =Column(Enum('PYTHON','FLASK','DJANGO')) # 枚举常规写法
tag2 =Column(Enum(TagEnum)) # 枚举另一种写法
create_time1=Column(Date)
create_time2=Column(DateTime)
create_time3=Column(Time)
content1 =Column(Text)
content2 =Column(LONGTEXT)
# Base.metadata.drop_all() #将Base上的ORM类模型对应数据中的表都删除
# Base.metadata.create_all() #创建Base上的ORM类到数据库中成为表
# 新增数据到表news中
session = sessionmaker(engine)()
news1 = News(price1=1000.0078,price2=1000.0078,title='测试数据',is_delete=True,tag1="PYTHON",tag2=TagEnum.flask,
create_time1=date(2018,12,12),create_time2=datetime(2019,2,20,12,12,30),create_time3=time(hour=11,minute=12,second=13),
content1="hello",content2 ="hello, hi, nihao")
news2 = News(price1=1000.0078,price2=1000.0078,title='测试数据',is_delete=False,tag1="PYTHON",tag2=TagEnum.python,
create_time1=date(2018,12,12),create_time2=datetime(2019,2,20,12,12,30),create_time3=time(hour=11,minute=12,second=13),
content1="hello",content2 ="hello hi nihao")
# session.add(news1)
session.add(news2)
session.commit()