Django之ORM查询操作
1、测试准备
1.1 终端打印ORM原生的sql语句
方法:把下面配置加入到settings中。
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
1.2 调用django环境建立测试文件
# 直接再项目下建立test.py文件 # 并把下面的语句添加进去 import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled15.settings") import django django.setup() from app01 import models
2、ORM查询操作
2.1 单表操作即增删改查
# 创建数据 book_obj = models.Book.objects.create() book_obj = models.Book() book_obj.save() # 编辑数据 models.Book.objects.filter().update() book_obj = models.Book.objects.filter().first() book_obj.name = 'SUN' book_obj.save() # 删除数据 models.Book.objects.filter().delete() book_obj = models.Book.objects.filter().first() book_obj.delete() # 了解即可 # 查看数据 models.Book.objects.all() models.Book.objects.filter()
2.2 all()
返回结果类型:QuerySet对象,(一个大列表)
说明:查询所有结果, 但是在django中做了优化,限制只取前21条数据
# 示例 books_obj = models.Book.objects.all() print(books_obj) # 结果:(列表中是一个个数据对象) # <QuerySet [<Book: Book object>, <Book: Book object>,...> # 强调: # 1. 可以使用索引取值,但不支持负数 print(books_obj[1]) # 结果是: Book object print(books_obj[-1]) # 结果是:异常AssertionError: Negative indexing is not supported. # 2. 内部优化,只取前21条,如果要拿到后面的数据,会再去取一次 books_obj = models.Book.objects.all() books_obj[22] # 执行的结果是:(使用上面的LOGGING配置打印sql语句) # (0.000) SELECT `app01_book`.`id`, `app01_book`.`name`, `app01_book`.`price`, `app01_book`.`publish_id` FROM `app01_book` LIMIT 21; args=() # (0.001) SELECT `app01_book`.`id`, `app01_book`.`name`, `app01_book`.`price`,`app01_book`.`publish_id` FROM `app01_book`; args=()
2.3 属性query
返回类型: Query对象
说明:调用后返回原生的sql语句,只能QuerySet对象使用
books_obj = models.Book.objects.all() print(books_obj.query) # SELECT `app01_book`.`id`, `app01_book`.`name`, `app01_book`.`price`, `app01_book`.`publish_id` FROM `app01_book`
2.4 filter(**kwargs) 和 exclude(**kwargs)
返回类型:QuerySet对象
说明:filter() 筛选出与所给筛选条件相匹配的对象,多个条件是and的关系,筛选条件可以是:对象,或字典
exclude()筛选出与所给筛选条件不匹配的对象,多个条件是and的关系
book_obj = models.Book.objects.filter(publish_id=1, price=45) for obj in book_obj: print(obj.id, obj.name, obj.price,obj.publish_id, obj.publish.name) book_obj = models.Book.objects.exclude(publish_id=1, price=45) for obj in book_obj: print(obj.id, obj.name, obj.price,obj.publish_id)
筛选条件:神奇的双下划线 "__"
|
常用的筛选条件的对应关系
|
|
|
sql语句筛选条件
|
django筛选条件
|
|
id in (1,2,3)
|
id__in=[1,2,3]
|
|
id > 2
|
id__gt = 2
|
|
id >= 2
|
id__gte = 2
|
|
id < 2
|
id__lt = 2
|
|
id <= 2
|
id__lte = 2
|
|
id between 10 and 20
|
id__range = [10, 20]
|
|
name like"sun%"
|
name__startswith = "sun"
|
|
name like "%sun%"
|
name_contains = "sun"
|
对于时间类型数据的查找: __year日期字段的年份 __month日期字段的月
__day日期字段的日# 示例: # 找到2019年的出版社 author = models.Publish.objects.filter(create_time__year="2019").values() # 找到2019年4月27日的出版社 from datetime import datetime author = models.Publish.objects.filter(create_time=datetime.datetime(2019, 4,27)).values() # 找到2019年4月份的出版社 from datetime import datetime, timedelta author = models.Publish.objects.filter(create_time__range=(datetime(2019,4,1), datetime(2019,5,1)-timedelta(days=1)))
2.5 order_by(*field)、reverse() 和 distinct()
返回类型:QuerySet对象
说明:order_by 对查询结果排序,支持'-id',负号表示降序;支持多个参数,可以有多个排序条件
reverse() 对排序后的结果反向排序。order_by("id").reverse()相当于order_by("-id")
distinct() 把取出的结果去重。在mysql中obj.values("id").distinct(), 在PostgreSQL中objects.distinct("id")
book_obj = models.Book.objects.order_by("price", "-id") # 说明:先按照"price"从小到大排序(升序),如果相等,按照"id"从大到小排序。
2.6 get()、first()和last()
返回类型:定义表的类的实例化对象
说明:first() 返回第一条记录
last() 返回最后一条记录
get() 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
book_obj = models.Book.objects print(book_obj.first()) print(book_obj.last()) print(book_obj.get(id=1)) # 结果是:三个Book object print(book_obj.get(price=45)) # 结果是报错: app01.models.MultipleObjectsReturned: get() returned more than one Book -- it returned 9! book_obj = models.Book.objects.filter(id__gt=3) # 条件:id > 3 print(book_obj.get(id=1)) # 结果是报错: app01.models.DoesNotExist: Book matching query does not exist.
2.7 values() 和values_list()
返回类型:QuerySet 对象
说明:values() 返回的是每个元素为字典的QuerSet 对象
values_list() 返回的是每个元素为元组的QuerSet 对象
models.Strudents.objects.values("id", "name") # 结果: <QuerySet{"id": 1, "name": "sun"}, {"id": 2, "name": "yw"}> models.Strudents.objects.values_list("id", "name") # 结果: <QuerySet(1, "sun"), (2, "yw")>
2.8 count()
返回类型:整数类型
说明:返回数据库中匹配查询(QuerySet)的对象数量
book_obj = models.Book.objects.filter(id__gt=3) print(book_obj.count())
2.9 exists()
返回类型:bool类型
说明:对查询出来的QuerySet进行有误数据的判断,有就返回True,否则返回False;可以直接用queryset对象判断
返回False;可以直接用queryset对象判断 book_obj = models.Book.objects.filter(id__gt=3) pprint(book_obj.exists()) # 以下两种方式效果一样 if book_obj: pass if book_obj.exists(): pass
2.10 aggregate(*args, **kwargs)
返回类型:字典
功能:对筛选的结果进行聚合
from django.db.models import Avg, Max, Min, Sum, Count book = models.Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) print(book) # 结果: # {'price__avg': 52.956522, 'price__max': Decimal('123.00'), 'price__min': Decimal('1.00')} # 可以设置key名 book = models.Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) print(book) # {'avg_price': 52.956522, 'max': Decimal('123.00'), 'min': Decimal('1.00')}
2.11 annotate()
返回类型:QuerSet对象
说明:分组,调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数),如果涉及到跨表,则会先关联join,再分组查询。
# 统计每种价格的书本数 book_list = models.Book.objects.values("price").annotate(num=Count("id")) print(book_list.query) print(book_list) # 结果: # SELECT `app01_book`.`price`, COUNT(`app01_book`.`id`) AS `num` FROM `app01_book` GROUP BY `app01_book`.`price` ORDER BY NULL # <QuerySet [{'price': Decimal('45.00'), 'num': 9}, {'price': Decimal('35.00'), 'num': 1}...]> # 分析: # 如果annotate前写values,则values内的字段即分组条件,得到的结果是一个个字典组成的QuerySet对象 # 如果annotate前不写values,则默认以该表的id分组,得到的是一个个表的对象组成的QuerySet对象,如: book_list = models.Book.objects.annotate(num=Count("id")) print(book_list.query) print(book_list) # 结果: # SELECT `app01_book`.`id`, `app01_book`.`name`, `app01_book`.`price`, `app01_book`.`publish_id`, COUNT(`app01_book`.`price`) AS `num` FROM `app01_book` GROUP BY `app01_book`.`id` ORDER BY NULL # <QuerySet [<Book: Book object>, <Book: Book object> '...(remaining elements truncated)...']> # 示例1: # 统计每本数作者个数 book_list = models.Book.objects.annotate(num=Count("authors")).values_list('name','num') print(book_list) # 结果: # SELECT `app01_book`.`name`, COUNT(`app01_book2author`.`author_id`) AS `num` FROM `app01_book` LEFT OUTER JOIN `app01_book2author` ON (`app01_book`.`id` = `app01_book2author`.`book_id`) GROUP BY `app01_book`.`id` ORDER BY NULL # <QuerySet [('绩效使能', 2), ('址簿', 2) '...(remaining elements truncated)...']>
注意: 如果报错: django.db.utils.InternalError:(1055, "'djangoday3.app01_book.name' isn't in GROUP BY") 原因: 数据库设置了"ONLY_FULL_GROUP_BY",这个模式表示,分组之后只能拿到分组的字段, 取消方法: 配置文件my.ini中取消,或: select @@sql_mode; set global sql_mde = "上面的结果去掉ONLY_FULL_GROUP_BY"
2.12 F查询与Q查询
说明:F("字段")支持同一张表的两个不同字段比较,同时F()支持与常数之间的加减乘除和取模运算
from django.db.models import F res = models.Book.objects.filter(maichu__gt=F('kucun')).values('name') Book.objects.all().update(price=F("price")+30)
Q()查询可以提供复杂查询,支持and,or, not,对应的是&(,),|,~
from django.db.models import Q res = models.Book.objects.filter(Q(name='三体')|Q(price='128)) # or res = models.Book.objects.filter(Q(name='三体'),Q(price='128')) # and res = models.Book.objects.filter(name='三体',price='128') # and res = models.Book.objects.filter(~Q(price='128')) # not Q 另一种用法 q1 = Q() q1.connector = "OR" q1.children.append(("id", 1)) q1.children.append(("id", 2)) q2 = Q() q2.connector = "OR" q2.children.append(("c1", 1)) q2.children.append(("c1", 2)) conn = Q() conn.add(q1, "AND") conn.add(q2, "AND") 变成另一种写法: condition_dict = { "q1": [("id", 1), ("id", 2)], "q2": [("c1", 1), ("c1", 2)] } conn = Q() for key, value in condition_dict.items(): q = Q() q.connector = "OR" for i in v: q.children.append(i) conn.add(q, "AND")
2.13 extra()
说明:支持额外的查询条件以及相关表、排序
# 语法: models.Book.objects.extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) #参数说明: # 映射 # select = {"a": "....%s.....", "b": "...%s..."} (value值是原生sql语句) # select_params = [1,2] (按顺序对应上面的%s) # 条件 # where = ["...%s..", "...", "%s"] (每个元素都可以是原生sql语句),and连接 # params = [1,2,3](按顺序对应上面的%s) # 表 # tables = [] # 排序 # order_by = [...] # 示例: res = models.Book.objects.extra( select={"nums": "select count(1) from app01_author where id > %s"}, select_params=[1], where=["price > %s"], params=[45], tables=["app01_author"], order_by=["id"] ) # 对应的sql语句 # SELECT # `app01_book`.`id`, # `app01_book`.`name`, # `app01_book`.`price`, # `app01_book`.`publish_id`, # (select count(1) from app01_author where id > 1) AS `nums`, # FROM # `app01_book`, # `app01_author` # WHERE # (price > 45) # ORDER BY # `app01_book`.`id` ASC
# 对查找到的字段起别名 # 第一种方法:extra(select={"new_name": "old_name"})(不能用于连表字段), Users.objects.filter().extra(select={'new_name': 'old_name'}).values('new_name') # 第二种方法:.annotate(new_names=F("old_name")), 可用于连表字段 Users.objects.filter(id=1).annotate(new_name=F('old_name')).values('new_name') 或者 authors = Author.objects.values("name","authorinfo__addr").annotate(addr=F("authorinfo__addr"))
2.14 原生sql语句
from django.db import connection, connections cursor = connection.cursor() # cursor = connections["default"].cursor(), 和上句效果一样 cursor.execute("select * from app01_book") # res = cursor.fetchall() # res = cursor.fetchone() res = cursor.fetchmany(2) print(res)
2.15 defer() 和 only()(查询优化)
说明:only("a") 只取a字段,但也能取出其他字段只是需要重新查询数据库
defer("a") 除a字段之外,的所有字段
books = models.Book.objects.filter(id__lt=3).only("price") for book in books: print(book.price) # 结果: # 45.00 # 78.00 # sql语句 # (0.000) SELECT `app01_book`.`id`, `app01_book`.`price` FROM `app01_book` WHERE `app01_book`.`id` < 3; args=(3,) books = models.Book.objects.filter(id__lt=3).only("price") for book in books: print(book.name) # 结果: # 绩效使能 # 地址簿 (0.000) SELECT `app01_book`.`id`, `app01_book`.`price` FROM `app01_book` WHERE `app01_book`.`id` < 3; args=(3,) (0.001) SELECT `app01_book`.`id`, `app01_book`.`name` FROM `app01_book` WHERE `app01_book`.`id` = 1; args=(1,) (0.001) SELECT `app01_book`.`id`, `app01_book`.`name` FROM `app01_book` WHERE `app01_book`.`id` = 2; args=(2,)
2.16 dates() 和datetimes()
def dates(self, field_name, kind, order='ASC'): """ 根据时间进行某一部分进行去重查找并截取指定内容 kind只能是:"year"(年), "month"(年-月), "day"(年-月-日) order只能是:"ASC" "DESC" 并获取转换后的时间 - year : 年-01-01 - month: 年-月-01 - day : 年-月-日 """ # 示例 publish_dates = models.Publish.objects.dates("create_time", "month") print(publish_dates) # 结果: # <QuerySet [datetime.date(2019, 2, 1), datetime.date(2019, 4, 1), datetime.date(2019, 5, 1)]> # (0.001) SELECT DISTINCT CAST(DATE_FORMAT(`app01_publish`.`create_time`, '%Y-%m-01') AS DATE) AS `datefield` FROM `app01_publish` WHERE `app01_publish`.`create_time` IS NOT NULL ORDER BY `datefield` ASC LIMIT 21; args=() def datetimes(self, field_name, kind, order='ASC', tzinfo=None): """ # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间 # kind只能是 "year", "month", "day", "hour", "minute", "second" # order只能是:"ASC" "DESC" # tzinfo时区对象 """ ... # 示例: models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC) models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai')) """ pip3 install pytz import pytz pytz.all_timezones pytz.timezone(‘Asia/Shanghai’) """
2.17 none()
说明:得到一个空的QuerySet对象
models.Book.objects.none() #结果: <QuerySet []>
2.18 bulk_create()(数据库优化)
说明:批量创建
bulk_create(self, objs, batch_size=None) # 参数: objs: 列表 batch_size: 表示一次插入的个数,<999个 # 示例: objs = [models.Publish(name="aaa", email="1@qq.com"), ...] models.Publish.objects.bulk_create(objs, 100)
2.19 get_or_create 和 update_or_create()
get_or_create(self, defaults=None, **kwargs) # 说明: # 如果存在,则获取,否则,创建 # defaults 指定创建时,其他字段的值 # 示例: author, is_created = models.Author.objects.get_or_create(name="sun", defaults={"authorinfo": 2}) print(author, is_created) # 存在的结果:Author object False # 不存在的结果:Author object True update_or_create(self, defaults=None, **kwargs) # 如果存在,则更新,否则,创建 # defaults 指定创建时或更新时的其他字段 # 使用方法如上
2.20 in_bulk()
说明:根据主键进行的查找(得到的是字典格式)
book1 = models.Book.objects.in_bulk([1,2,3]) print(book1) book2 = models.Book.objects.filter(id__in = [1,2,3]) print(book2) 结果: {1: <Book: Book object>, 2: <Book: Book object>, 3: <Book: Book object>} <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]>

浙公网安备 33010602011771号