SQLAlchemy04 /SQLAlchemy查询高级
SQLAlchemy04 /SQLAlchemy查询高级
1、排序
排序概述:
order_by:可以指定根据这个表中的某个字段进行排序,如果在前面加了一个-,代表的是降序排序。
在模型定义的时候指定默认排序:有些时候,不想每次在查询的时候都指定排序的方式,可以在定义模型的时候就指定排序的方式。有以下两种方式:
relationship的order_by参数:在指定relationship的时候,传递order_by参数来指定排序的字段。
在模型定义中,添加以下代码,即可让文章使用标题来进行排序。
__mapper_args__ = {
"order_by": title
}
正序排序与倒序排序:默认是使用正序排序。如果需要使用倒序排序,那么可以使用这个字段的
desc()方法,或者是在排序的时候使用这个字段的字符串名字,然后在前面加一个负号。
代码示例:
class Article(Base):
__tablename__ = 'article'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(50), nullable=False)
create_time = Column(DateTime,nullable=False,default=datetime.now)
uid = Column(Integer,ForeignKey("user.id")) author = relationship("User",backref=backref("articles")) __mapper_args__ = {
"order_by": create_time.desc()
} def __repr__(self):
return "<Article(title:%s,create_time:%s)>" % (self.title,self.create_time) # 倒序排序
articles = session.query(Article).all()
print(articles)
2、limit、offset和切片操作
limit、offset和切片操作概述:
- limit:可以限制每次查询的时候只查询几条数据。
- offset:可以限制查找数据的时候过滤掉前面多少条。
- 切片:可以对Query对象使用切片操作,来获取想要的数据。可以使用
slice(start,stop)方法来做切片操作。也可以使用[start:stop]的方式来进行切片操作。一般在实际开发中,中括号的形式是用得比较多的。希望大家一定要掌握。示例代码如下:
articles = session.query(Article).order_by(Article.id.desc())[0:10]
代码示例:
3、懒加载
懒加载概述:
1、在一对多,或者多对多的时候,如果想要获取多的这一部分的数据的时候,往往能通过一个属性就可以全部获取了。比如有一个作者,想要或者这个作者的所有文章,那么可以通过user.articles就可以获取所有的。但有时候我们不想获取所有的数据,比如只想获取这个作者今天发表的文章,那么这时候我们可以给relationship传递一个lazy='dynamic',以后通过user.articles获取到的就不是一个列表,而是一个AppenderQuery对象了。这样就可以对这个对象再进行一层过滤和排序等操作。
2、通过lazy='dynamic',获取出来的多的那一部分的数据,就是一个AppenderQuery对象了。这种对象既可以添加新数据,也可以跟Query一样,可以再进行一层过滤。
总而言之一句话:如果你在获取数据的时候,想要对多的那一边的数据再进行一层过滤,那么这时候就可以考虑使用lazy='dynamic'。
3、lazy可用的选项:select:这个是默认选项。还是拿user.articles的例子来讲。如果你没有访问user.articles这个属性,那么sqlalchemy就不会从数据库中查找文章。一旦你访问了这个属性,那么sqlalchemy就会立马从数据库中查找所有的文章,并把查找出来的数据组装成一个列表返回。这也是懒加载。dynamic:这个就是我们刚刚讲的。就是在访问user.articles的时候返回回来的不是一个列表,而是AppenderQuery对象。
代码示例:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(String(50),nullable=False) class Article(Base):
__tablename__ = 'article'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(50), nullable=False)
create_time = Column(DateTime,nullable=False,default=datetime.now)
uid = Column(Integer,ForeignKey("user.id")) author = relationship("User",backref=backref("articles",lazy="dynamic")) def __repr__(self):
return "<Article(title: %s)>" % self.title """
Base.metadata.drop_all()
Base.metadata.create_all() user = User(username='zhilio')
for x in range(100):
article = Article(title="title %s" % x)
article.author = user
session.add(article)
session.commit()
""" from sqlalchemy.orm.collections import InstrumentedList
from sqlalchemy.orm.dynamic import AppenderQuery
from sqlalchemy.orm.query import Query
user = session.query(User).first()
# 是一个Query对象
print(user.articles.filter(Article.id > 50).all())
# 可以继续追加数据进去
article =Article(title='title 100')
user.articles.append(article)
session.commit()
4、group_by
根据某个字段进行分组。比如想要根据性别进行分组,来统计每个分组分别有多少人,那么可以使用以下代码来完成:
session.query(User.gender,func.count(User.id)).group_by(User.gender).all()
5、having
having是对查找结果进一步过滤。比如只想要看未成年人的数量,那么可以首先对年龄进行分组统计人数,然后再对分组进行having过滤。示例代码如下:
result = session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age >= 18).all()
代码示例:
from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey,Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker,relationship,backref HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'first_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root' # dialect+driver://username:password@host:port/database
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE) engine = create_engine(DB_URI) Base = declarative_base(engine) session = sessionmaker(engine)() class User(Base):
__tablename__ = 'user'
id = Column(Integer,primary_key=True,autoincrement=True)
username = Column(String(50),nullable=False)
age = Column(Integer,default=0)
gender = Column(Enum("male","female","secret"),default="male") """
Base.metadata.drop_all()
Base.metadata.create_all() user1 = User(username='王五',age=17,gender='male')
user2 = User(username='赵四',age=17,gender='male')
user3 = User(username="张三",age=18,gender='female')
user4 = User(username="刘二",age=19,gender='female')
user5 = User(username="彭一",age=20,gender='female') session.add_all([user1,user2,user3,user4,user5])
session.commit()
""" # 每个年龄的人数
# from sqlalchemy.orm.query import Query
result = session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age < 18).all()
print(result)
6、join
join概述:
- join分为left join(左外连接)和right join(右外连接)以及内连接(等值连接)。
- 参考的网页:http://www.jb51.net/article/15386.htm
- 在sqlalchemy中,使用join来完成内连接。在写join的时候,如果不写join的条件,那么默认将使用外键来作为条件连接。
- query查找出来什么值,不会取决于join后面的东西,而是取决于query方法中传了什么参数。就跟原生sql中的select 后面那一个一样。
比如现在要实现一个功能,要查找所有用户,按照发表文章的数量来进行排序。示例代码如下:
result = session.query(User,func.count(Article.id)).join(Article).group_by(User.id).order_by(func.count(Article.id).desc()).all()
代码示例:
#encoding: utf-8 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey,Table
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker,relationship,backref
# 在Python3中才有这个enum模块,在python2中没有
import enum
from datetime import datetime
import random HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'first_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root' # dialect+driver://username:password@host:port/database
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE) engine = create_engine(DB_URI) Base = declarative_base(engine) session = sessionmaker(engine)() class User(Base):
__tablename__ = 'user'
id = Column(Integer,primary_key=True,autoincrement=True)
username = Column(String(50),nullable=False) def __repr__(self):
return "<User(username: %s)>" % self.username class Article(Base):
__tablename__ = 'article'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(50), nullable=False)
create_time = Column(DateTime, nullable=False, default=datetime.now)
uid = Column(Integer,ForeignKey("user.id")) author = relationship("User",backref="articles") def __repr__(self):
return "<Article(title: %s)>" % self.title """
Base.metadata.drop_all()
Base.metadata.create_all() user1 = User(username='zhiliao')
user2 = User(username='ketang') for x in range(1):
article = Article(title='title %s' % x)
article.author = user1
session.add(article)
session.commit() for x in range(1,3):
article = Article(title='title %s' % x)
article.author = user2
session.add(article)
session.commit()
""" # 找到所有的用户,按照发表的文章数量进行排序
result = session.query(User,func.count(Article.id)).join(Article).group_by(User.id).order_by(func.count(Article.id).desc()).all()
print(result) # sql语句:
# select user.username,count(article.id) from user join article on user.id=article.uid group by user.id order by count(article.id) desc;
7、subquery
subquery概述:
子查询可以让多个查询变成一个查询,只要查找一次数据库,性能相对来讲更加高效一点。不用写多个sql语句就可以实现一些复杂的查询。那么在sqlalchemy中,要实现一个子查询,应该使用以下几个步骤:
- 将子查询按照传统的方式写好查询代码,然后在
query对象后面执行subquery方法,将这个查询变成一个子查询。 - 在子查询中,将以后需要用到的字段通过
label方法,取个别名。 - 在父查询中,如果想要使用子查询的字段,那么可以通过子查询的返回值上的
c属性拿到。
整体的示例代码如下:
stmt = session.query(User.city.label("city"),User.age.label("age")).filter(User.username=='李A').subquery()
result = session.query(User).filter(User.city==stmt.c.city,User.age==stmt.c.age).all()
- 将子查询按照传统的方式写好查询代码,然后在
代码示例:
from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey,Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker,relationship,backref HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'first_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root' # dialect+driver://username:password@host:port/database
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE) engine = create_engine(DB_URI) Base = declarative_base(engine) session = sessionmaker(engine)() class User(Base):
__tablename__ = 'user'
id = Column(Integer,primary_key=True,autoincrement=True)
username = Column(String(50),nullable=False)
city = Column(String(50),nullable=False)
age = Column(Integer,default=0) def __repr__(self):
return "<User(username: %s)>" % self.username """
Base.metadata.drop_all()
Base.metadata.create_all() user1 = User(username='李A',city="长沙",age=18)
user2 = User(username='王B',city="长沙",age=18)
user3 = User(username='赵C',city="北京",age=18)
user4 = User(username='张D',city="长沙",age=20) session.add_all([user1,user2,user3,user4])
session.commit()
""" # 寻找和李A这个人在同一个城市,并且是同年龄的人
user = session.query(User).filter(User.username=='李A').first()
users = session.query(User).filter(User.city==user.city,User.age==user.age).all()
print(users) # 子查询
stmt = session.query(User.city.label("city"),User.age.label("age")).filter(User.username=='李A').subquery()
result = session.query(User).filter(User.city==stmt.c.city,User.age==stmt.c.age).all()
print(result)
SQLAlchemy04 /SQLAlchemy查询高级的更多相关文章
- SQLAlchemy(四):SQLAlchemy查询高级
目录 SQLAlchemy04 /SQLAlchemy查询高级 1.排序 2.limit.offset和切片操作 3.懒加载 4.group_by 5.having 6.join 7.subquery ...
- sqlalchemy(二)高级用法
sqlalchemy(二)高级用法 本文将介绍sqlalchemy的高级用法. 外键以及relationship 首先创建数据库,在这里一个user对应多个address,因此需要在address上增 ...
- tornado 07 数据库—ORM—SQLAlchemy—查询
tornado 07 数据库—ORM—SQLAlchemy—查询 引言 #上节课使用query从数据库查询到了结果,但是query返回的对象是直接可用的吗 #在query.py内输入一下内容 from ...
- sqlalchemy 查询姿势总结
sqlalchemy查询使用 1.带条件查询 查询是最常用的,对于各种查询我们必须要十分清楚,首先是带条件的查询 #带条件查询 rows = session.query(User).filter_by ...
- T-SQL查询高级--理解SQL SERVER中非聚集索引的覆盖,连接,交叉和过滤
写在前面:这是第一篇T-SQL查询高级系列文章.但是T-SQL查询进阶系列还远远没有写完.这个主题放到高级我想是因为这个主题需要一些进阶的知识作为基础..如果文章中有错误的地方请不吝指正.本篇文章 ...
- SQLAlchemy查询
SQLAlchemy查询 结果查询: from databases.wechat import User from config import session def search(): result ...
- 把SQLAlchemy查询对象转换成字典
1-假设查出来的为单个对象 1-1 在model.py中为模型对象添加字典转换函数: from exts import db class User(db.Model): __tablename__ = ...
- SQLAlchemy ORM高级查询之过滤,排序
order_by,filter的语法. 用久了才会熟悉. Session = sessionmaker(bind=engine) session = Session() print(session.q ...
- sqlalchemy查询结果类型简析
Sqlalchemy的查询方式有很多种,例如可以查询全部,可以查询符合条件的,可以查询指定字段的.那么这么多种查询,返回的结果是不是一样的呢?作本文记录分析结果. Sql_forengin.py #c ...
随机推荐
- Js中Array 函数使用方法
遇到数组有关操作,脑子第一反应不要再是嵌套 for 循环了,Array 类型提供了一些遍历有关的函数. Array.prototype.forEach() : 把数组每个元素丢到一个处理 functi ...
- layui 通过laytpl模板,以及laypage分页实现
一.引用js依赖 jquery-1.11.3.min.js , layui.all.js, json2.js 二.js分页方法封装(分页使用模板laytpl) 1.模板渲染 /** * 分页模板的渲 ...
- Jmeter使用beanshell对数据进行加密传输
首先,来看一下接口签名加密规则 1.需要参于签名的参数: a. 在请求参数列表中,除去 cliSign 参数外,其他需要使用到的参数皆是要签名的参数. 2.生成签名字符串 a. 没有值的参数无需传递, ...
- 跨云厂商部署 k3s 集群
原文链接:https://fuckcloudnative.io/posts/deploy-k3s-cross-public-cloud/ 最近一两年各大云服务商都出了各种福利活动,很多小伙伴薅了一波又 ...
- Java基础-Java中transient有什么用-序列化有那几种方式
此文转载于知乎的一篇文章,看着写的非常全面,分享给大家. 先解释下什么是序列化 我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术. Java序列化 ...
- JavaWeb网上图书商城完整项目--day02-18.修改密码页面处理
1.用户登陆成功之后会显示 当点击修改密码的时候,会进入下面的页面 对应的是pwd.jsp这个文件 我们把对jsp页面前段的校验都封装在pwd.js中,在jsp中引入该js文件 <%@ page ...
- AbstractQueuedSynchronizer和ReentranLock基本原理
先把我主要学习参考的文章放上来先,这篇文章讲的挺好的,分析比较到位,最好是先看完这篇文章,在接下去看我写的.不然你会一脸懵逼,不过等你看完这篇文章,可能我的文章对你也用途不大了 深入分析Abstrac ...
- 苹果XR手机的音频体验测试总结
苹果XR手机的音频 苹果XR算是苹果手机历史上一个里程碑的型号了,是苹果憋了两年的大招,连苹果9的称号就不要了.直接是X.说明苹果对它给予的希望很大.作为一个音频算法工程师,一直想体验一下XR的音 ...
- 并发06--JAVA中的并发工具类
1.等待多线程完成的CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作. 使用join也可以完成这个操作,代码示例如下: package com.exam ...
- python文件处理-根据txt列表将文件从其他文件夹 拷贝到指定目录
内容涉及:路径拼接,文件拷贝,内容追加(append) # !/usr/bin/python # -*- coding: UTF-8 -*- import pandas as pd import os ...