Django 数据库相关操作二

以下表数据为例:
在这里插入图片描述

查询

选择字段:

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)
)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久醉绕心弦,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值