1、ORM基础操作

注意点:
①创建新表时必须写Base.metadata.create_all(),数据库中已存在这张表就可以不写(写了不会报错),代表将创建的(类)表映射到数据库中,如果数据库中已经存在这个表了,则不会改变表结构,如果后续操作有冲突则会报错(比如添加一个表中不存在的字段记录),如果没冲突则会往已存在的表里面做操作
②写入数据库中的流程类似于git,先add在commit,要通过实例sessionmaker在调用它的实例化对象使用,为什么这么用具体看代码注释
③通过实例化创建的类可以添加想要的数据进入内存,通过add将数据添加到数据库,通过commit实现入库的操作
④添加一条数据session.add(stu1)添加多条数据session.add_all([stu1,stu2,…])

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
USERNAME = 'root'
PASSWORD = 'root'
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'mytest'
BD_URL = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
engine = create_engine(BD_URL)
Base = declarative_base(engine)
class Student(Base):
    __tablename__ = 'student' # 固定的写法一定要这么写源码规定的
    id = Column(Integer,primary_key=True,autoincrement=True)
    name = Column(String(50),nullable=False)
# Base.metadata.create_all()  
stu = Student(name='wchao')  # 将实例化的对象写入内存
print(stu.name,stu.id)  # 还没写入数据库,所以stu.name获取的到,stu.id获取不到
Session = sessionmaker(bind=engine)# 类的实例化
session = Session()  # 里面有__call__方法可以将实例化对象变成函数去调用
session.add(stu)  # 添加到数据库,但是没有保存,要提交之后才可以保存
session.commit()  # 提交

2、通过ORM实现CRUD

注意:CRUD(增删改查)
①删除数据不要采用物理删除,最好给记录添加is_del字段进行逻辑删除
②回滚结合try except使用,如果有异常则进行回滚,没有直接提交,提交之后的数据是不能进行回滚的
③所有的操作除了查询之外都需要commit

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker


USERNAME = 'root'
PASSWORD = 'root'
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'mytest'
BD_URL = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
engine = create_engine(BD_URL)
Base = declarative_base(engine)
class Article(Base):
    __tablename__ = 'art'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(50))
    author = Column(String(50))

    def __str__(self):  # 查询的时候定义的方法,直接调用类的时候会返回数据,就不用类.属性这样复杂的写了
        return 'Article(id:{},title:{},content:{},author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

# 增
def add_data():
    article1 = Article(title='python', content='人生苦短,我用python', author='龟叔')
    article2 = Article(title='java', content='人生苦短,我用java', author='家叔')
    article3 = Article(title='c', content='人生苦短,我用c', author='草叔')
    session.add(article1)  # 添加一条数据
    session.add_all([article1, article2, article3])
    session.commit()

# 查
def search_data():
    # data = session.query(Article).all()  # all查询所有,返回的是一个列表对象
    # print(data) # 打印表中的每一条记录的地址
    # for item in data:
    #     print(item)
    #     print(item.title)
    # 下面是两种带有条件的查询写法
    # data = session.query(Article).filter(Article.title=='python').all()
    # print(data[0])
    # data = session.query(Article).filter_by(title='python').all()
    # print(data[0])
    # 查询第一条记录,以及自定义想要查询的是哪一条数据
    data = session.query(Article).first()
    print(data)
    data = session.query(Article).get(4)  # 4是id为4的记录,没有返回None,以主键的值为查询的数
    print(data)

# 改
def update_data():
    data = session.query(Article).first()
    data.author = 'wchao'
    print(data.author)  # wchao
    session.rollback()  # 回滚,类似于撤销操作
    print(data.author)  # 龟叔
    session.commit()  # 提交之后还是龟叔,没有改变数据库中的内容
# 删
def delete_data():  # 最好使用逻辑删除,使用修改默认字段的方式来防止误操作上面的物理删除
    data = session.query(Article).get(1)
    session.delete(data)
    session.commit()

# 主函数入口
if __name__ == '__main__':
    # add_data()
    # search_data()
    # update_data()
    delete_data()

3、sqlalchemy常用的数据类型

想要用什么数据类型就要通过from sqlalchemy import 类型进行导入后才可以使用
Folat :浮点类型,应用场景,钱、身高、体重等只会精确到小数点后面的第4位后面的后面的就四舍五入
DECIMAL(arg1,arg2): 定点类型(总共有多少位,保留几位小数),如果小数位没有给够,后面会补上0
Boolean:布尔传True和False进去数据库中会显示1和0,可以作为逻辑删除的is_del字段
Enum:枚举,性别,数据库中只能保存列举的枚举类型,存没有的就会报错
Date:年月日要传递datetime.date()进去
Time:时分秒要传递datetime.date()进去
DateTime:年月日时分秒要传递datetime.date()进去
String:字符类型,需要指定长度,要和Text区分
Text:文本类型
LONGTEXT:长文本类型,一般用于文本内容,要注意导入方式
视频、图片、音乐一般保存路径
测试方法

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String,Float,DECIMAL
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.dialects.mysql import LONGTEXT

USERNAME = 'root'
PASSWORD = 'root'
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'mytest'
BD_URL = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
engine = create_engine(BD_URL)
Base = declarative_base(engine)
class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(60))
    price = Column(Float)
    price1 = Column(DECIMAL(20,5))
    
Base.metadata.drop_all()  # 删除映射的表才能对修改字段的类型
Base.matedata.create_all()
Session = sessionmaker(bind=engine)
session = Session()
user = User(name='wchao',price=12.23456,price1=10.23145698)
session.add()

4、column常用的参数

default:默认值
nullable:是否为空,nullable=False,不允许为空
primary_key:是否为主键
unique:是否唯一,唯一表示字段里面的内容不可以重复,但是可以为null
autoincrement:是否自增
onupdate:修改记录时自动触发update_time=Column(DateTime,onupdate=datetime.now())
name:该属性在数据库中的字段映射,name=Column(‘字段名’,String(50))

5、query的聚合命令以及使用

①模型对象指定查找这个模型中的所有对象
result = session.query(Article).all()查询出来是一个对象列表
②模型中的属性,可以指定查找模型的几个属性
print(result[0].name)返回出来的就是数据库第一条记录中对应的name字段的值
③聚合函数:要导入func才可以使用,from sqlalchemy import func
func.count:统计行的数量
func.avg:求平均值
func.max:求最大值
func.min:求最小值
func.sum:求和

from sqlalchemy import func
result1 = session.query(func.count(Article.id))
print(result1) # 返回的是原生的sql语句
result2 = session.query(func.count(Article.id)).first()
print(result2) # 返回的是查询的结果,以元组形式返回
result3 = session.query(func.count(Article.id)).filter(Article.title=='python').first()
print(result3) # 可以结合filter使用,注意func传入的位置

6、过滤条件

from sqlalchemy import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
# 查询表中title字段中记录为title0的记录内容,不是的话变==为!=
result = session.query(Article[映射的表对象的名称]).filter(Article.title == 'title0').all
# 模糊查找记录中含有title内容的记录
result = session.query(Article).filter(Article.title.like('%title%')).all()
# in在什么里面 和 notin_(可以写成~)不在什么里面 [1,4]是查1和4,不是1到4
result = session.query(Article).filter(Article.title.in_(['title0','titel2']))
result = session.query(Article).filter(~Article.title.in_(['title0','titel2']))
# is null注意,null是None(没有开辟内存空间),如果数据里什么都不写就是非None(开辟了内存空间)
result = session.query(Article).filter(User.name==None)
result = session.query(Article).filter(User.name.is_(None))
# and
from sqlalchemy import and_  # 只有使用and_才需要导入,其它的写法不用导入
result = session.query(Article).filter(Article.title=='title0',Article.id==0).all()
result = session.query(Article).filter(and_(Article.title=='title0',Article.id==0)).all()
result = session.query(Article).filter(Article.title=='title0').filter(Article.id==0).all()
# or 满足其中的一个条件就可以查询出来
from sqlalchemy import or_
result = session.query(Article).filter(or_(Article.title=='title0',Article.id==0)).all()
for every in result:
	print(every)