以下表数据为例:
查询
选择字段:
values(*fields, *kwargs):
返回一个QuerySet,这个QuerySet返回一个字典列表,而不是数据对象。参数fields 指定了select中我们想要限制查询的字段。返回的字典中只会包含我们指定的字段。如果不指定,包含所有字段。
In [1]: Student.objects.values('name')
Out[2]: (0.046) SELECT `student`.`name` FROM `student` ORDER BY `student`.`create_time` DESC LIMIT 21; args=()
<QuerySet [{'name': 'test1'}, {'name': 'test'}]>
In [3]: Student.objects.values('name')[0]
(0.047) SELECT `student`.`name` FROM `student` ORDER BY `student`.`create_time` DESC LIMIT 1; args=()
Out[4]: {'name': 'test1'}
only(fields):
返回一个QuerySet.参数fields指定了select中我们想要限制查询的字段。注意,only一定包含主键字段,此时返回的是对象。
In [15]: Student.objects.only('name')
Out[15]: (0.031) SELECT `student`.`id`, `student`.`name` FROM `student` ORDER BY `student`.`create_time` DESC LIMIT 21; args=()
(0.047) SELECT `student`.`id`, `student`.`hobby` FROM `student` WHERE `student`.`id` = 2 LIMIT 21; args=(2,)
(0.031) SELECT `student`.`id`, `student`.`hobby` FROM `student` WHERE `student`.`id` = 1 LIMIT 21; args=(1,)
<QuerySet [<Student: name:test1,hobby:唱歌>, <Student: name:test,hobby:玩游戏>]>
# 返回的是对象
In [19]: type(Student.objects.only('name')[0])
(0.031) SELECT `student`.`id`, `student`.`name` FROM `student` ORDER BY `student`.`create_time` DESC LIMIT 1; args=()
Out[19]: project2s.models.Student
defer(fields) :
返回一个QuerySet。参数fields指定了select中我们想要排除的查询字段。注意,defer一定包含主键字段
In [27]: Student.objects.defer('name','age')
Out[27]: (0.031) SELECT `student`.`id`, `student`.`gender`, `student`.`hobby`, `student`.`create_time` FROM `student` ORDER BY `student`.`create_time` DESC LIMIT 21; args=()
<QuerySet [<Student: hobby:唱歌>, <Student: hobby:玩游戏>]>
条件查询
在filter,exclude,get中可以接收参数实现各种比较条件的查询。
exact
准确匹配.如果给的值是None,它会被解释成SQL NULL 看下面的案例
Project.objects.get(id__exact=14)
Project.objects.get(id__exact=None)
id__exact=14等价于id = 14,默认情况不带exact
In [28]: Student.objects.filter(id__exact=1)
Out[28]: (0.031) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE `student`.`id` = 1 ORDER
BY `student`.`create_time` DESC LIMIT 21; args=(1,)
<QuerySet [<Student: name:test,hobby:玩游戏>]>
iexact
不区分大小写的匹配
In [33]: Student.objects.get(name__iexact='test3')
(0.031) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE `student`.`name` LIKE 'test3' LIMI
T 21; args=('test3',)
Out[33]: <Student: name:TEST3,hobby:跳舞>
in
在一个给定的可迭代对象中,通常是一个列表,元组,或queryset。虽然不是经常用但是字符串也可以。
In [35]: Student.objects.filter(id__in=[1,2])
Out[35]: (0.031) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE `student`.`id` IN (1, 2)
ORDER BY `student`.`create_time` DESC LIMIT 21; args=(1, 2)
<QuerySet [<Student: name:test1,hobby:唱歌>, <Student: name:test,hobby:玩游戏>]>
gt 大于
In [38]: Student.objects.filter(age__gt=20)
Out[38]: (0.047) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE `student`.`age` > 20 ORDE
R BY `student`.`create_time` DESC LIMIT 21; args=(20,)
<QuerySet [<Student: name:TEST3,hobby:跳舞>, <Student: name:test1,hobby:唱歌>]>
gte 大于等于
In [40]: Student.objects.filter(age__gte=28)
Out[40]: (0.031) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE `student`.`age` >= 28 ORD
ER BY `student`.`create_time` DESC LIMIT 21; args=(28,)
<QuerySet [<Student: name:TEST3,hobby:跳舞>, <Student: name:test1,hobby:唱歌>]>
lt 小于
In [43]: Student.objects.filter(age__lt=28)
Out[43]: (0.031) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE `student`.`age` < 28 ORDE
R BY `student`.`create_time` DESC LIMIT 21; args=(28,)
<QuerySet [<Student: name:test,hobby:玩游戏>]>
lte 小于等于
In [44]: Student.objects.filter(age__lte=28)
Out[44]: (0.047) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE `student`.`age` <= 28 ORD
ER BY `student`.`create_time` DESC LIMIT 21; args=(28,)
<QuerySet [<Student: name:test1,hobby:唱歌>, <Student: name:test,hobby:玩游戏>]>
range 范围区间
In [46]: Student.objects.filter(age__range=(20,28))
Out[46]: (0.047) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE `student`.`age` BETWEEN 2
0 AND 28 ORDER BY `student`.`create_time` DESC LIMIT 21; args=(20, 28)
<QuerySet [<Student: name:test1,hobby:唱歌>]>
条件组合
AND
使用 SQL AND 操作符将两个 QuerySet 组合起来。
以下运行结果一致:
In [50]: Student.objects.filter(age=28)& Student.objects.filter(name='test1')
Out[50]: (0.032) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE (`student`.`age` = 28 AND
`student`.`name` = 'test1') ORDER BY `student`.`create_time` DESC LIMIT 21; args=(28, 'test1')
<QuerySet [<Student: name:test1,hobby:唱歌>]>
In [51]: Student.objects.filter(age=28,name='test1')
Out[51]: (0.031) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE (`student`.`age` = 28 AND
`student`.`name` = 'test1') ORDER BY `student`.`create_time` DESC LIMIT 21; args=(28, 'test1')
<QuerySet [<Student: name:test1,hobby:唱歌>]>
In [52]: from django.db.models import Q
In [53]: Student.objects.filter(Q(age=28) & Q(name='test1'))
Out[53]: (0.047) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE (`student`.`age` = 28 AND
`student`.`name` = 'test1') ORDER BY `student`.`create_time` DESC LIMIT 21; args=(28, 'test1')
<QuerySet [<Student: name:test1,hobby:唱歌>]>
OR
使用 SQL OR 操作符将两个 QuerySet 组合起来,以下结果运行一致:
In [50]: Student.objects.filter(age=28) | Student.objects.filter(name='test1')
Out[50]: (0.032) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE (`student`.`age` = 28 AND
`student`.`name` = 'test1') ORDER BY `student`.`create_time` DESC LIMIT 21; args=(28, 'test1')
<QuerySet [<Student: name:test1,hobby:唱歌>]>
In [52]: from django.db.models import Q
In [53]: Student.objects.filter(Q(age=28) | Q(name='test1'))
Out[53]: (0.047) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time` FROM `student` WHERE (`student`.`age` = 28 AND
`student`.`name` = 'test1') ORDER BY `student`.`create_time` DESC LIMIT 21; args=(28, 'test1')
<QuerySet [<Student: name:test1,hobby:唱歌>]>
聚合查询
count 统计数量
In [3]: Student.objects.count()
(0.031) SELECT COUNT(*) AS `__count` FROM `student`; args=()
Out[3]: 3
In [5]: Student.objects.filter(age__gt=20).count()
(0.047) SELECT COUNT(*) AS `__count` FROM `student` WHERE `student`.`age` > 20; args=(20,)
Out[5]: 2
Avg 平均值
计算年龄平均值
In [9]: from django.db.models import Avg
In [10]: Student.objects.aggregate(avg_age = Avg('age'))
(0.047) SELECT AVG(`student`.`age`) AS `avg_age` FROM `student`; args=()
Out[10]: {'avg_age': 25.3333}
Max 最大值
In [12]: from django.db.models import Max
In [13]: Student.objects.aggregate(max_age = Max('age'))
(0.047) SELECT MAX(`student`.`age`) AS `max_age` FROM `student`; args=()
Out[13]: {'max_age': 30}
Min 最小值
In [14]: from django.db.models import Min
In [15]: Student.objects.aggregate(min_age = Min('age'))
(0.047) SELECT MIN(`student`.`age`) AS `min_age` FROM `student`; args=()
Out[15]: {'min_age': 18}
Sum 求和
In [16]: from django.db.models import Sum
In [17]: Student.objects.aggregate(sum_age = Sum('age'))
(0.047) SELECT SUM(`student`.`age`) AS `sum_age` FROM `student`; args=()
Out[17]: {'sum_age': 76}
分组查询
表里新增几条数据:
分组,聚合,需要结合values,annotate和聚合方法看下面的案例
查询男女生多少人
通过性别分组:
In [4]: from django.db.models import Count
In [5]:
# annotate 默认按照主键分组Student.objects.values('gender').annotate(Count('gender'))
Out[5]: (0.047) SELECT `student`.`gender`, COUNT(`student`.`gender`) AS `gender__count` FROM `student` GROUP BY `student`.`gender` ORDER BY NULL LIMIT 21; args=()
<QuerySet [{'gender': 1, 'gender__count': 3}, {'gender': 0, 'gender__count': 2}]>
关联对象操作与多表查询
学生表:
班级表:
一对多
正向
一个模型如果有一个外键字段,通过这个模型对外键进行操作叫做正向
更新:
通过属性赋值的方式
In [17]: s1 = Student(name='张三',age=21,hobby='玩')
In [18]: s1.save()
(0.047) INSERT INTO `student` (`name`, `gender`, `hobby`, `age`, `create_time`, `grade_id`) VALUES ('张三', 1, '玩', 21, '2021-11-15 07:17:17.619059', NULL) RETURNING `student`.`id`; a
rgs=('张三', 1, '玩', 21, '2021-11-15 07:17:17.619059', None)
In [19]: g= Grade.objects.get(id=2)
(0.032) SELECT `grade`.`id`, `grade`.`name`, `grade`.`class_num` FROM `grade` WHERE `grade`.`id` = 2 LIMIT 21; args=(2,)
In [20]: g
Out[20]: <Grade: Grade object (2)>
In [21]: s1.grade =g
In [22]: s1.save()
(0.031) UPDATE `student` SET `name` = '张三', `gender` = 1, `hobby` = '玩', `age` = 21, `create_time` = '2021-11-15 07:17:17.619059', `grade_id` = 2 WHERE `student`.`id` = 4; args=('张
三', 1, '玩', 21, '2021-11-15 07:17:17.619059', 2, 4)
注意,主表表数据要入库(也即是Grade对象要save()之后)之后,引用表才能创建
ForeignKey字段的更新,和普通字段没有什么区别。
删除
如果一个外键字段有null=True的设置(即,它允许空值),那么可以指定None来删除关系。
In [14]: s1 = Student.objects.get(id=4)
(0.062) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time`, `student`.`grade_id` FROM `student` WHERE `student`.`i
d` = 4 LIMIT 21; args=(4,)
In [15]: s1
Out[15]: <Student: name:张三,hobby:玩>
In [16]: s1.grade = None
In [17]: s1.save()
(0.031) UPDATE `student` SET `name` = '张三', `gender` = 1, `hobby` = '玩', `age` = 21, `create_time` = '2021-11-15 07:17:17.619059', `grade_id` = NULL WHERE `student`.`id` = 4; args=(
'张三', 1, '玩', 21, '2021-11-15 07:17:17.619059', 4)
连表查询
查询课程名为音乐的学生
In [5]: Student.objects.filter(grade__name='音乐').values('name')
Out[5]: (0.047) SELECT `student`.`name` FROM `student` INNER JOIN `grade` ON (`student`.`grade_id` = `grade`.`id`) WHERE `grade`.`name` = '音乐' LIMIT 21; args=('音乐',)
<QuerySet [{'name': 'test'}]>
外键字段对象的属性可以通过两个下划线来获取。
反向
查询
一个模型如果被另外一个模型外键关联,通过这个模型对关联它的模型进行操作叫做反向
如果一个模型有一个ForeignKey,那么这个外键模型的实例将可以访问一个返回第一个模型的所有实例的管理器。默认情况下,这个管理器名为FOO_set,其中FOO是源模型名,小写。这个管理器返回queryset。
通过课程表查询学生信息:
In [5]: g1.student_set
Out[5]: <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager at 0x18b495e67f0>
In [6]: g1.student_set.all()
Out[6]: (0.046) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time`, `student`.`grade_id` FROM `student` WHERE `stu
dent`.`grade_id` = 2 LIMIT 21; args=(2,)
<QuerySet [<Student: name:test1,hobby:画画>]>
通过在定义字段的时候设置参数 related_name 可以替代上面的管理器名
新增
管理器的create方法,通过主表创建从表数据
In [13]: g1.student_set.create(name='阿三',age=22,hobby='play')
(0.031) INSERT INTO `student` (`name`, `gender`, `hobby`, `age`, `create_time`, `grade_id`) VALUES ('阿三', 1, 'play', 22, '2021-11-15 07:59:14.919685', 2) RETURNING `student`.`id`; ar
gs=('阿三', 1, 'play', 22, '2021-11-15 07:59:14.919685', 2)
Out[13]: <Student: name:阿三,hobby:play>
增加多条数据
In [8]: ss = Student.objects.create(name='laa',age=35)
(0.047) INSERT INTO `student` (`name`, `gender`, `hobby`, `age`, `create_time`, `grade_id`) VALUES ('laa', 1, NULL, 35, '2021-11-15 08:09:04.240228', NULL) RETURNING `student`.`id`; ar
gs=('laa', 1, None, 35, '2021-11-15 08:09:04.240228', None)
In [9]: ss1 = Student.objects.create(name='aa',age=36)
(0.031) INSERT INTO `student` (`name`, `gender`, `hobby`, `age`, `create_time`, `grade_id`) VALUES ('aa', 1, NULL, 36, '2021-11-15 08:09:15.139102', NULL) RETURNING `student`.`id`; arg
s=('aa', 1, None, 36, '2021-11-15 08:09:15.139102', None)
In [10]: g.student_set.add(ss,ss1)
(0.047) UPDATE `student` SET `grade_id` = 1 WHERE `student`.`id` IN (14, 15); args=(1, 14, 15)
删除
从相关对象中移除指定的模型对象
In [18]: s = Student.objects.get(name='laa')
(0.032) SELECT `student`.`id`, `student`.`name`, `student`.`gender`, `student`.`hobby`, `student`.`age`, `student`.`create_time`, `student`.`grade_id` FROM `student` WHERE `student`.`n
ame` = 'laa' LIMIT 21; args=('laa',)
In [19]: g
Out[19]: <Grade: Grade object (1)>
In [20]: g.student_set.remove(s)
(0.031) UPDATE `student` SET `grade_id` = NULL WHERE (`student`.`grade_id` = 1 AND `student`.`id` IN (14)); args=(1, 14)
删除多个
g.student_set.remove(s1, s2, ...)
清空全部
从相关对象中删除所有的 对象
g.student_set.clear()
修改
替换对象集,可以先清空后在添加:
g.student_set.clear()
g.student_set.add(ss,ss1)
通过set直接替换,传入列表:
g.student_set.set([ss2,ss3])
查询
与objects使用一致
g.student_set.all() # 查询全部
g.student_set.filter(name='test') # 条件查询
related_name
可以给外键通过related_name字段重新赋值管理器名称
grade = models.ForeignKey('Grade', on_delete=models.CASCADE, null=True, related_name='students')
In [4]: g.students
Out[4]: <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager at 0x1b6f9ad6eb0>
多对多
多对多两端都可以获得另一端的自动API访问。该API的工作原理类似上面的“反向”一对多关系。一个不同之处在于:定义ManyToManyField的模型使用该字段本身的属性名,而“反向”模型使用原始模型的小写模型名,加上“_set”(就像反向一对多关系一样)。
# 添加
c1.students.add(s1, s2, s3)
s1.course_set.add(c1, c2, c3)
# 查询
c1.students.all()
c1.students.filter(name='test')
和ForeignKey一样ManyToMany也可以指定related_name。在上面的案例中,如果定义在Course中的ManyToManyField指定related_name=‘courses’,那么每一个Student对象都会有一个course的属性替代course_set.
c1.students.all()
s1.courses.all()
使用manaytomany之后,这两个表可以有反向的api直接相互访问。
一对一
一对一关系非常类似于多对一关系。如果您在模型上定义一对一字段,那么该模型的实例将可以通过模型的一个简单属性访问相关对象。例如:
d1 = StudentDetail(num='2019020001', college='武汉理工大学')
s1.detail = d1
s1.save()
不同之处在于“反向”查询。一对一关系中的相关模型也可以访问一个Manager对象,但是这个Manager只表示一个对象,而不是对象的集合:
d1.student # 返回一个student对象
如果没有给这个关系分配对象,Django将抛出一个DoesNotExist异常。
实例可以以与分配正向关系相同的方式分配到反向关系:
d2.student = s
跨表查询
Django提供了一种强大而直观的方法,可以在查询中“跟踪”关系,在幕后自动处理SQL连接。要跨越关系,只需使用跨模型的相关字段的字段名,以双下划线分隔,直到到达想要的字段为止。
举例:
查询男生都报名了什么课程
Course.objects.filter(students__sex=1).distinct()
这个关系要多深就可以有多深。它也向后工作。要引用“反向”关系,只需使用模型的小写名称。
查询所有报名了美术课程的学员:
Student.objects.filter(course__name__contains='美术')
查询所有报名了美术的一班的学员:
Student.objects.filter(course__name__contains='美术', grade__num__contains='1')
执行原生SQL
第一种方式:
执行原生查询并返回模型实例
在管理器上调用raw()方法用于执行远程SQL查询,就会返回模型实例:
Manager.raw(raw_query, params=(), translations=None)
该方法接受一个原生 SQL 查询语句,执行它,并返回一个 django.db.models.query.RawQuerySet 实例。这个 RawQuerySet 能像普通的 QuerySet一样被迭代获取对象实例。
举例:
查询age大于18的学生
In [12]: for i in Student.objects.raw("select * from student where age >%s",[18]):
...: print(i)
...:
(0.047) select * from student where age >18; args=(18,)
name:test3,hobby:玩游戏
name:张三,hobby:玩
name:李四,hobby:play
name:阿三,hobby:play
name:ls,hobby:None
name:laa,hobby:None
name:aa,hobby:con
name:ceaaa,hobby:11
name:111,hobby:
第二种方式:
直接执行自定义的SQL
In [13]: from django.db import connection
In [14]: cursor = connection.cursor()
In [15]: cursor.execute("select * from student where age >%s",[18])
(0.047) select * from student where age >18; args=[18]
Out[15]: 9
In [16]: cursor.fetchone()
Out[16]: (3, 'test3', 1, '玩游戏', 19, datetime.datetime(2021, 11, 15, 7, 8, 19, 49699), 4)
In [17]: cursor.fetchall()
Out[17]:
(
(4,'张三',1,'玩',21,datetime.datetime(2021, 11, 15, 7, 17, 17,619059),None),
(5,'李四',1,'play',112,datetime.datetime(2021, 11, 15, 7, 56,56,936666),2),
(8,'阿三',1,'play',22,datetime.datetime(2021, 11, 15, 7, 59, 14,919685),2),
(13,'ls',1,None,33,datetime.datetime(2021, 11, 15, 8, 8, 33,612185),None)
)