今日内容概要
- 更多查询方式
- 连表查询
- 原生sql
- flask-sqlalchemy使用
今日内容详细
更多查询方式
查询
1.查询: filer:写条件 filter_by:等于的值
.all() 查询所有 是list对象
res = session.query(User).all() # 是个普通列表
print(type(res))
print(len(res))
只查询某几个字段
# select name as xx,email from user;
res = session.query(User.name.label('name1'), User.email)
print(res) # SELECT users.name AS name1, users.email AS users_email FROM users
print(res.all()) # [('nanaok', '@qq.com'), ('nanaok', '22@qq.com'), ('nanaok', '222@qq.com'), ('yyyy', '11@qq.com')]
for item in res.all():
print(item[0]) # nanaok...
filter、filter_by
# filter传的是表达式,filter_by传的是参数
res = session.query(User).filter(User.name == "nana").all()
res = session.query(User).filter(User.name != "nana").all()
res = session.query(User).filter(User.name != "nana", User.email == '3@qq.com').all() # 且
and条件
# django 中使用 Q (与 或 非)
res = session.query(User).filter_by(name='nana').all()
res = session.query(User).filter_by(name='nana',email='47@qq.com').all()
.all() 查询所有
res = session.query(User).first()
res = session.query(User).all()
print(type(res)) # <class 'list'> 取一个 all了后是list,list 没有first方法
查询所有,使用占位符(了解)
:value :name
select * from user where id <20 or name=lqz
res = session.query(User).filter(text("id<:value or name=:name")).params(value=20, name='nana').all()
自定义查询(了解)
from_statement 写纯原生sql
res=session.query(User).from_statement(text("SELECT * FROM users where email=:email")).params(email='11@qq.com').all()
print(type(res[0])) # <class 'models.User'>
print(res[0].name) # yyyy
高级查询
表达式,and条件连接
res = session.query(User).filter(User.id > 1, User.name == 'nana').all() # and条件
between
res = session.query(User).filter(User.id.between(1, 9), User.name == 'nana').all()
res = session.query(User).filter(User.id.between(1, 9)).all()
in
res = session.query(User).filter(User.id.in_([1,2,3])).all()
print(res) # [yyyy, nanaok]
res = session.query(User).filter(User.email.in_(['11@qq.com','r@qq.com'])).all()
print(res) # [yyyy]
~非,除...外
res = session.query(User).filter(~User.id.in_([1,3,4])).all()
print(res)
二次筛选
res = session.query(User).filter(~User.id.in_(session.query(User.id).filter_by(name='nana'))).all()
print(res)
"""
SELECT *
FROM users
WHERE (users.id NOT IN (SELECT users.id
FROM users
WHERE users.name = %(name_1)s))
"""
and or条件
from sqlalchemy import and_, or_
# or_包裹的都是or条件,and_包裹的都是and条件
res = session.query(User).filter(and_(User.id >= 3, User.name == 'nana')).all() # and条件
res = session.query(User).filter(User.id < 3, User.name == 'nana').all() # 等同于上面
res = session.query(User).filter(or_(User.id < 2, User.name == 'nana')).all()
res = session.query(User).filter(or_(User.id < 2,and_(User.name == 'nana', User.id > 3),User.extra != ""))
通配符
res = session.query(User).filter(User.email.like('%@%')).all()
# select user.id from user where user.name not like e%;
# 以e开头,不以e开头
res = session.query(User.id).filter(~User.name.like('e%'))
res = session.query(User).filter(~User.name.like('e%')).all()
分页
# 一页2条,查第5页
res = session.query(User)[2*5:2*5+2]
排序
res = session.query(User).order_by(User.email.desc()).all()
res = session.query(Book).order_by(Book.price.desc()).all()
res = session.query(Book).order_by(Book.price.asc()).all()
# 第一个条件重复后,再按第二个条件升序排
res = session.query(User).order_by(User.name.desc(), User.id.asc())
分组查询
from sqlalchemy.sql import func
# 分组后,只能拿分组字段和聚合函数字典,如果拿别的,是严格模式,会报错
res = session.query(User).group_by(User.extra) # 如果是严格模式,就报错
# 分组之后取最大id,id之和,最小id 和分组的字段
from sqlalchemy.sql import func
res = session.query(
User.name,
func.max(User.id),
func.sum(User.id),
func.min(User.id),
func.avg(User.id)).group_by(User.name).all()
for item in res:
print(item)
# 分组后having
# select name,max(id),sum(id),min(id) from user group by user.name having id_max>2;
from sqlalchemy.sql import func
res = session.query(
User.name,
func.max(User.id),
func.sum(User.id),
func.min(User.id)).group_by(User.name).having(func.max(User.id) > 2).all()
print(res)
连表查询
笛卡尔积后过滤
# select * from Person, Hobby where Person.hobby_id == Hobby.id
res = session.query(Person, Hobby).filter(Person.hobby_id == Hobby.id).all()
print(res) # [(nana, 篮球), (cx, 羽毛球)]
for item in res:
print(type(item))
print(item[0])
内连接
# select * from Person inner join Hobby on Person.hobby_id=Hobby.id; # 内连接
res = session.query(Person).join(Hobby) # 没有写on谁---》自动关联外键 默认inner join
print(res)
res = session.query(Person).join(Hobby,Person.id == Hobby.id) # 自己自定on---》自动关联外键
print(res)
res = session.query(Person).join(Hobby,Person.hobby_id == Hobby.id) # 自己自定on---》正确的
res = session.query(Person).join(Hobby,Person.id == Hobby.id) # 自己自定on---》sql本身错误
左连接
isouter=True 外连,表示Person left join Favor,没有右连接,反过来即可
# select * from Person left join Hobby on Person.hobby_id=Hobby.id; # 内连接
res = session.query(Person).join(Hobby,Person.hobby_id == Hobby.id,isouter=True)
右连接
# select * from Hobby left join Person on Person.hobby_id=Hobby.id;
res = session.query(Hobby).join(Person,isouter=True)
print(res)
多表连接
方式一:直接连
#select * FROM boy, girl, boy2girl WHERE boy.id = boy2girl.boy_id AND girl.id = boy2girl.girl_id
res = session.query(Boy, Girl,Boy2Girl).filter(Boy.id == Boy2Girl.boy_id,Girl.id == Boy2Girl.girl_id).all()
print(res)
方式二:join连
# SELECT* FROM boy INNER JOIN boy2girl ON boy.id = boy2girl.boy_id INNER JOIN girl ON girl.id = boy2girl.girl_id WHERE boy.id >= %(id_1)s
res = session.query(Boy).join(Boy2Girl).join(Girl).filter(Boy.id>=2)
print(res)
原生sql(django-orm如何执行原声sql)
1.有的复杂sql 用orm写不出来---》用原生sql查询
2.原生sql查询,查出的结果是对象
3.原生sql查询,查询结果列表套元组
sqlalchemy执行原生sql
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import create_engine,text
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/db001", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()
方式一
查询
sql = text('select * from users')
cursor = session.execute(sql)
result = cursor.fetchall()
print(result) # 列表套元组
添加
sql = text('insert into users(name,email) values(:name,:email)')
cursor = session.execute(sql,params={"name": 'lqz', 'email': '3333@qq.com'})
session.commit()
print(cursor.lastrowid) # 9
session.close()
方式二
以后都用session操作--->socpe_session线程安全)一般不用
conn = engine.raw_connection()
cursor = conn.cursor()
cursor.execute(
"select * from users"
)
result = cursor.fetchall()
print(result)
方式三
res = session.query(User).from_statement(text("SELECT * FROM boy where name=:name")).params(name='nana').all()
Django执行原生sql
# 执行完的结果映射到对象中---》上面讲的 方式三:
from model import Book
books_obj_list = Book.objects.raw('select distinct id, book_name from test_book')
for book_obj in books_obj_list:
print(book_obj.id, book_obj.book_name)
# 纯原生sql
from django.db import connection
cur=connection.cursor()
cur.execute('select distinct id, book_name from test_book')
print(cur.fetch_all())
cur.close()
with connection.cursor() as cur:
cur.execute('select distinct id, book_name from test_book')
Flask_sqlalchemy使用
1.sqlalchemy 集成到flask中
第三方: flask-sqlalchemy 封装了用起来,更简洁
使用flask-sqlalchemy集成
2.步骤
0. pip install flask-sqlalchemy
1.导入 from flask_sqlalchemy import SQLAlchemy
2.实例化得到对象
db = SQLAlchemy()
3.将db注册到app中
db.init_app(app)
4.视图函数中使用session
全局的db.session # 线程安全的
5.models.py 中继承Model
db.Model
6.写字段
username = db.Column(db.String(80), unique=True, nullable=False)
7.配置文件中加入
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root@127.0.0.1:3306/ddd?charset=utf8"
SQLALCHEMY_POOL_SIZE = 5
SQLALCHEMY_POOL_TIMEOUT = 30
SQLALCHEMY_POOL_RECYCLE = -1
# 追踪对象的修改并且发送信号
SQLALCHEMY_TRACK_MODIFICATIONS = False
文件
flask_sqlalchemy
-src
--__init__.py
--models.py
--settings.py
--views.py
-manage.py
init.py
from flask import Flask
# 1.导入:
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 第二步:实例化得到对象
db = SQLAlchemy()
app.config.from_pyfile('settings.py')
# 第三步:注册到app中
db.init_app(app)
from .views import user
app.register_blueprint(user)
models.py
# 第四步:在models中,找所有东西 都从db中拿
from src import db
class User(db.Model):
# 以__开头的是配置
__tablename__ = 'users' # 数据库表名称,如果不写,以类名作为表名
id = db.Column(db.Integer, primary_key=True) # 主键索引,聚簇索引
name = db.Column(db.String(64), index=True, nullable=False) # name字段加辅助索引
email = db.Column(db.String(32), unique=True)
__table_args__ = (
db.UniqueConstraint('id', 'name', name='uix_id_name'), # 联合唯一
db.Index('ix_id_name', 'name', 'email'), # 索引
)
def __str__(self):
return self.name
def __repr__(self):
return self.name
settings.py
DEBUG=True
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:ln1998151125@127.0.0.1:3306/db001?charset=utf8"
SQLALCHEMY_POOL_SIZE = 5
SQLALCHEMY_POOL_TIMEOUT = 30
SQLALCHEMY_POOL_RECYCLE = -1
# 追踪对象的修改并且发送信号
SQLALCHEMY_TRACK_MODIFICATIONS = False
views.py
from flask import Blueprint
from .models import User
user = Blueprint('user', __name__)
from src import db
@user.route('/')
def index():
res = db.session.query(User).filter_by(name='lqz').all()
print(res)
return 'asdfasdf'
manage.py
from src import app
if __name__ == '__main__':
app.run()
项目--源码
flask-migrate使用
1.表,字段发生变化,都会有记录,自动同步到数据库中-->django支持这种操作
2.原生的sqlalchemy,不支持修改表的
3.flask-migrate可以实现类似于django的
python manage.py makemigrations #记录
python manage.py migrate #真正的同步到数据库
4.使用步骤
0.flask:2.2.2 flask-script:2.0.3 flask-migrate==2.7.0
1.第一步:安装,依赖于flask-script
pip3.8 install flask-migrate==2.7.0
2.在app所在的py(启动)文件中
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
manager = Manager(app)
# flask-script可以自定义命令---》
# flask-migrate本质是它借助于flask-script增加了几个命令来对数据库表和字段进行管理
Migrate(app, db) # sqlalchemy的db对象
manager.add_command('db', MigrateCommand)
manager.run() # 以后使用python manage.py runserver 启动项目
3.以后第一次执行一下
python manage.py db init # 生成一个migrations文件夹,里面以后不要动,记录迁移的编号
4.以后在models.py 写表,加字段,删字段,改参数
5.只需要执行
python manage.py db migrate # 记录
python manage.py db upgrade # 真正的同步进去