tornado SQLAlchemy

简介

tornado没有像Django那样提供了内建的ORM,需要使用第三方的SQLAlchemy来实现。

ORM全称:Object Relational Mapping 对象关系映射

好处:通过ORM可以不用关心后台是使用的哪种数据库,只需要按照ORM所提供的语法规则去书写相应的代码,ORM就会自动转换成对应的数据库SQL语句。

SQLAlchemy不仅仅只是用于tornado开发,它可以用于任何ORM场合。

补充:

ORM叫对象关系映射,mysql是关系型数据库。而redis、mongodb它们是非关系数据库,以键值对形式表示数据,根本没有关系可言,所以没有ORM这一说法。

一、准备工作

1.安装好mysql

2.安装好所需的依赖:pymysql、sqlalchemy

二、SQLAlchemy连接数据库

(一).导包

from sqlalchemy import create_engine

(二).设置连接的参数

HOSTNAME = '127.0.0.1'

PORT = '3306'

DATABASE = 'mydb'

USERNAME = 'admin'

PASSWORD = 'Root110qwe'

(三).定义连接数据库的URL

db_url = 'mysql+pymysql://{}:{}@{}/{}?charset=utf8'.format(USERNAME,PASSWORD,HOSTNAME,DATABASE)

注意:顺序绝对不要弄错了,也不要有任何空格!解析是通过字符串分割的,有一个不对就报错。

(四).连接数据库

engine = create_engine(db_url)

(五).测试连接

connection = engine.connect()

result = connection.execute('select 1')

print(result.fetchone())

如有打印出了结果:"(1,)",那么就可以了。

(六).完整代码

# connect.py

from sqlalchemy import create_engine


HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'mydb'
USERNAME = 'admin'
PASSWORD = 'Root110qwe'

db_url = 'mysql+pymysql://{}:{}@{}/{}?charset=utf8'.format(USERNAME,PASSWORD,HOSTNAME,DATABASE)

engine = create_engine(db_url)
connection = engine.connect()
result = connection.execute('select 1')
print(result.fetchone())
View Code

三、在数据库里面新建表

(一).创建Module的Base类

接上面connect.py中的代码,加入下面两行代码:

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base(engine)

对象关系型映射,数据库中的表与python中的类相对应,创建的类必须继承自sqlalchemy中的基类。

使用declarative方法定义的映射类依据一个基类,这个基类是维系类和数据表关系的目录。

应用通常只需要有一个Base的实例,declarative_base()功能创建一个基类。

(二).创建Module

from datetime import datetime
from sqlalchemy import Column, Integer, String, DateTime
from connect import Base


class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(20), nullable=False)
    password = Column(String(50))
    creatime = Column(DateTime, default=datetime.now)
View Code

用类来表示数据库中的表,这些表的类都继承于我们的Base基类,在类里面我们定义一些属性,这个属性通过映射,就对应表里面的字段。

__tablename__ 是固定写法,表示要映射到数据库中的表名。绝对不能把这个单词写错了!

(三).映射到数据库中

Base.metadata.create_all()

执行此代码,就会把创建好的Module映射到数据库中

四、单表的增删改查

(一).创建会话

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(engine)
session = Session()
View Code

对数据库的表进行增删改查之前,先需要建立会话,建立会话之后才能进行操作,就类似于文件要打开之后才能对文件内容操作

(二).add(增)

(1).添加一条数据

person = User(username='buodng', password='qwe123')
session.add(person)
session.commit()
View Code

(2).添加多条数据

session.add_all([User(username='tuple', password=2), User(username='which', password=3)])

(三).delete(删)

rows = session.query(User).filter(User.username=='budong')[0]
print(rows)
session.delete(rows)
session.commit()
View Code

(四).update(改)

rows = session.query(User).filter(User.username=='budong').update({User.password:1})
session.commit()
View Code

(1).小技巧1

更新数据可以使用commit()方法,直接更新

(五).query(查)

rows = session.query(User).all()

rows = session.query(User).first()

query就是查询的意思,在SQLAlchemy中用来查询数据。

all()查询所有

first()查询第一条数据

(六).总结

除查询之外,其他的增删改都必须要手动调用session.commit()才能让数据生效

五、查询深入篇-基本查询

(一).导库、导模块

from connect import session

from user_modules import User

(二).查询结果

(1).查询出来的是一个query对象

rs = session.query(User).filter(User.username == 'budong')
print(rs, type(rs))  # 打印出了一条SQL语句
View Code

rs是一个query对象

使用SQLAlchemy时,如果想要查看最终在数据库中执行的sql,可以通过上述方式来查看

(2).all()

session.query(User).filter(User.username=='budong').all() 返回所有符合条件的数据

session.query(User.username).filter(User.username=='budong').all() 查询对象中的某个属性的值(对应为查询表中某个字段的值),返回的结果是一个列表

(3).first()

session.query(User).filter(User.username=='budong').first() 返回所有符合条件数据的第一条数据

session.query(User.username).filter(User.username=='budong').first() 返回的结果是一个元组

(4).[0]

session.query(User).filter(User.username=='budong')[0]

[0]和first()类似,但如果没有符合条件的数据则会报错

(5).取值方式

rs = session.query(User).filter(User.username=='budong').all()

有两种方式可以取到具体的数据值:

getattr(rs[0], 'username')

rs[0].username

(6).查询结果的总结

如果是整表查询则返回Module的一个实例;如果是查询某个属性,返回的则是具体的数据。

如果是Module实例,需要通过属性访问的方式取值。

六、查询深入篇-条件查询

(一).filter()

filter()是一个过滤函数,过滤条件都可以书写在此函数中,不同的条件之间用"逗号"分隔

session.query(User).filter(User.username=='budong').all()

(二).filter_by()

session.query(User).filter_by(username='budong').all()

(三).filter()和filter_by()之间的区别

(1).filter()中是双等号"==";而filter_by()中是单个等号"="

(2).filter()中需要添加"类对象",filter_by()不需要

(3).filter_by()中只能添加等于的条件,不能添加不等于、大于小于等条件,filter()没有这个限制

(四).like()和notlike()

like()是模糊查询,和数据库中的like用法一样,notlike和like作用相反

session.query(User.id).filter(User.username.like('budong%')).all()

session.query(User.id).filter(User.username.notlike('budong%')).all()

(五).in_和notin_

in_和notin_是范围查找

session.query(User.id).filter(User.username.in_(['budong', 'tuple'])).all()

session.query(User.id).filter(User.username.notin_(['budong', 'tuple'])).all()

(六).is_和isnot

is_和isnot是精确查找

session.query(User.id).filter(User.username.is_(None)).all()

session.query(User.id).filter(User.username.isnot(None)).all()

判断为空还可以使用:

session.query(User.id).filter(User.username==None).all()

(七).limit()

session.query(User.username).filter(User.username!='budong').limit(2).all() # 这里是查看前两条数据

(八).offset()

session.query(User.username).filter(User.username!='budong').offset(1).all() # 这里是偏移一条记录

(九).slice()

slice()对查询出来的数据进行切片取值

session.query(User.username).filter(User.username!='budong').slice(1,3).all()

(十).one()

one()查询一条数据,如果存在多条则报错

session.query(User.username).filter(User.username=='tuple').one()

(十一).order_by()

order_by()对查询出来的结果进行排序,默认是顺序

session.query(User.username).filter(User.username!='budong').order_by(User.id).all()

(十二).desc()

desc()是倒序排序

from sqlalchemy import desc # 使用desc()必须导入这个包

session.query(User.username).filter(User.username!='budong').order_by(desc(User.username)).all()

(十三).order_by()和limit()一起使用

session.query(User.username).filter(User.username!='budong').order_by(User.username).limit(3).all()

(十四).or_

或的意思,和数据库中的or一样

(1).导包

from sqlalchemy import or_

(2).session.query(User.username).filter(or_(User.username.isnot(None), User.password=='qwe123')).all()

七、查询深入篇-函数的使用

(一).导包

from sqlalchemy import func,extract

(二).func.count()和group_by()一起配合使用

session.query(User.password,func.count(User.id)).group_by(User.password).all()

group_by()和order_by()不需要导入,可以直接使用

(三).func.count()+group_by()+having()一起配合使用

session.query(User.password, func.count(User.id)).group_by(User.password).having(func.count(User.id)>1).all()

having()可以直接使用

(四).func.sum() 求和

session.query(User.password, func.sum(User.id)).group_by(User.password).all()

(五).func.max() 求最大值

session.query(User.password, func.max(User.id)).group_by(User.password).all()

(六).func.min() 求最小值

session.query(User.password, func.min(User.id)).group_by(User.password).all()

(七).extract()

(1).session.query(extract('minute',User.creatime).label('minute'), func.count(User.id)).group_by('minute').all()

extract()提取对象中的数据,这里提取分钟,并把提取出来的结果用label命名别名,之后就可以使用group_by()来分组

(2).session.query(extract('day',User.creatime).label('day'), func.count('*')).group_by('day').all()

count()里面同样可以使用星号"*"

八、多表查询

(一).新建一个Module

from sqlalchemy import ForeignKey

class UserDetails(Base):
    __tablename__ = 'user_details'

    id = Column(Integer, primary_key=True, autoincrement=True)
    id_card = Column(Integer, nullable=True, unique=True)
    lost_login = Column(DateTime)
    login_num = Column(Integer, default=0)
    user_id = Column(Integer, ForeignKey('user.id'))

    def __repr__(self):
        return '<UserDetails(id=%s,id_card=%s,last_login=%s,login_num=%s,user_id=%s)>' % (
            self.id, self.id_card, self.lost_login, self.login_num, self.user_id
        )
View Code

(二).cross join

session.query(UserDetails, User).filter(UserDetails.id==User.id).all()

(三).inner join

session.query(User.username,UserDetails.lost_login).join(UserDetails,UserDetails.id==User.id).all()

(四).left join

session.query(User.username,UserDetails.lost_login).outerjoin(UserDetails,UserDetails.id==User.id).all()

(五).union

union是联合查询,有自动去重的功能,对应的还有union_all

q1 = session.query(User.id)
q2 = session.query(UserDetails.id)
q1.union(q2).all()
View Code

(六).声明子表和使用

sql_0 = session.query(UserDetails.lost_login).subquery()

使用子表:

session.query(User, sql_0.c.lost_login).all()

九、原生SQL查询

(一).写好SQL语句

sql_1='''select * from `user`'''

(二).执行查询

row = session.execute(sql_1)

(三).取值

row.fetchone()

row.fetchmany()

row.fetchall()

(四).循环取值

for i in row:print(i)

十、表关系

(一).一对一表关系

(1).导入方法

from sqlalchemy.orm import relationship

(2).引入之前使用的两个模型:User和UserDetails

(3).在UserDetails中添加如下代码

userdetail = relationship('User',backref='details',uselist=False,cascade='all')

uselist=False 这里表示一对一的关系(默认值为True表示一对多)

(4).使用

rows = session.query(User).get(1)

rows.details

(5).对上述操作的分析

自动添加属性:

User本来是没有details这个属性的,但是在UserDetails里面添加relationship之后,User实例会自动加上details属性。

relationship:

在MySQL中没有直接说明表关系的东西,外键约束是一个表现形式,它只是一种表之间的约束。是为了自己好理解,才把外键认为了是“表关系”。

在SQLAlchemy中,这个relationship默认代表的是一对多的关系,relationship是和外键一起使用的。可以通过参数设置去改变表关系,它默认是一对多的关系。而这个关系是SQLAlchemy里的,跟MySQL数据库没有关系。

(6).relationship参数分解

relationship('User', backref='details', uselist=False, cascade='all')

User:关联的Module

backref:在对应的Module中添加属性

uselist:上面的例子中表示“一对一”关系。如果是一对多关系,则不需要重新赋值。如果是一对一关系,则需要赋值为False

cascade:自动关系处理,就和MySQL中的 ON DELETE 类似

(7).cascade所有可选的值

all:所有操作都会自动处理到关联对象上

save-update:关联对象自动添加到会话

delete:关联对象自动从会话中删除

delete-orphan:属性中去掉关联对象,则会话中会自动删除关联对象

merge:session.merge()时会处理关联对象

refresh-expire:session.expire()时会处理关联对象

expunge:session.expunge()时会处理关联对象

(8).正方向查询

分辨正向查询和反向查询,主要看ForeginKey在哪个Module中

(二).多对多表关系

(1).先创建一个新的Model

class Article(Base):
    __tablename__ = 'article'

    id = Column(Integer, primary_key=True, autoincrement=True)
    content = Column(String(500), nullable=True)
    create_time = Column(DateTime, default=datetime.now)

    article_user = relationship('User', backref='article', secondary=user_article)

    def __repr__(self):
        return 'Article(id=%s, content=%s, creat_time=%s)' % (
            self.id, self.content, self.create_time
        )
View Code

(2).导入方法

from sqlalchemy import Table

(3).使用中间表来关联两张表之间的多对多关系

user_article = Table(
    'user_article', Base.metadata,
    Column('user_id', Integer, ForeignKey('user.id'), primary_key=True),
    Column('article_id', Integer, ForeignKey('article.id'), primary_key=True)
)
View Code
原文地址:https://www.cnblogs.com/quanquan616/p/9614157.html