【django】模型类中数据的增删改查操作总结

在人生的道路上,不管是潇洒走一回,或者是千山独行,皆须是自己想走的路,虽然,有的人并不是很快就能找到自己的方向和道路,不过,只要坚持到底,我相信,就一定可以找到自己的路,只要找到路,就不必怕路途遥远了。

导读:本篇文章讲解 【django】模型类中数据的增删改查操作总结,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

在这里插入图片描述


一、数据库数据操作

一旦创建数据模型后,django自动给与一套数据库 抽象API,用来创建、检索、更新和删除对象。
为了方便调试,可以通过下面的命令进入django shell

python manage.py shell

使用这个命令进入的shell环境会包含当前的django项目的依赖,直接通过python命令进入的shell不会包含django依赖。

在日志等级debug=True,下面的代码可以打印除所有执行过的sql

from django.db import connection
print(connection.queries)

二、创建对象

创建一个模型对象,可以直接通过关键字参数实例化,然后调用save方法,将其存入数据库

from crm.models import Student
s=Student(**fields)
s.save()

这在幕后执行的INSERT 语句

注意:django在调用save()方法才会操作数据。save()方法没有返回值

还有一种创建对象并一步到位的create()方法
使用管理器上的create方法,会直接写入数据库
create方法会返回创建的对象

Student.objects.create(**fields)

三、批量创建对象

方法一:for循环迭代

批量创建对象可以利用上面的方法和for循环结合使用,但是效率比较低,会执行多条sql

data=[
    {"name":"james","age":18,"phone":"13888888888"},
    {"name":"kelai","age":22,"phone":"13688888888"},
    {"name":"kd","age":19,"phone":"13888888777"},
]

for item in data:
    s=Student(**item)
    s.save()

方法二:bulk_create()

bulk_create()方法可以有效的将提供的对象插入到数据库表(一般来说,不管多少个数据,只需要一条sql),它返回创建的对象列表

data=[
    {"name":"harden","age":18,"phone":"13888878228"},
    {"name":"curry","age":22,"phone":"13688883388"},
    {"name":"ad","age":19,"phone":"13888855577"},
]


Student.objects.bulk_create([
    Student(**(data[0])),
    Student(**(data[1])),
    Student(**(data[2]))
])

执行的sql语句:

print(connection.queries[-1])
{'sql': "INSERT INTO `t_student` (`name`, `age`, `phone`, `address`, `create_time`, `channel_id`) VALUES ('harden', 18, '13888878228', NULL, '2023-01-06 07:21:25.347180', NULL), ('curry', 22, '13688883388', NULL, '2023-01-06 07:21:25.347180', NULL), ('ad', 19, '13888855577', NULL, '2023-01-06 07:21:25.347180', NULL) RETURNING `t_student`.`id`", 'time': '0.000'}

但是需要注意

1、save()方法不会被调用,所以pre_save和post_save信号不会被发送
2、多对多关系也处理不了
3、多表继承模式,不能与子模型一起工作

四、更新对象

save()默认更新所有的字段

在幕后,执行了update语句

In [1]: from crm.models import Student

In [2]: from django.db import connection

In [3]: s=Student.objects.get(id=1)

In [4]: s.age=24

In [5]: s.save()

In [6]: print(connection.queries[-1])
{'sql': "UPDATE `t_student` SET `name` = 'kb', `age` = 24, `phone` = '15202629656', `address` = NULL, `create_time`
= '2023-01-01 10:41:36.822670', `channel_id` = NULL WHERE `t_student`.`id` = 1", 'time': '0.047'}

save()方法默认会更新所有的字段,可以在调用save方法的时候传递参数update_fields一个字段名称列表,
这样只有列表中的字段才会被更新。优点轻微的提升性能

指定要更新的字段

s.save(update_fields=['age','name'])

In [7]: s.age=28

In [8]: s.save(update_fields=['age','name'])

In [9]: print(connection.queries[-1])
{'sql': "UPDATE `t_student` SET `name` = 'kb', `age` = 28 WHERE `t_student`.`id` = 1", 'time': '0.016'}

一次性更新多个对象

如果想要统一设置查询集中的所有对象的某个字段,可以使用update()方法

Student.objects.update(sex=1)

五、查询对象

1、管理器

每一个模型都有一个默认的管理器,用来操作数据表,主要是构建QuerySet
默认的管理器的名称就是objects,直接通过模型类调用。

In [19]: Student.objects
Out[19]: <django.db.models.manager.Manager at 0x18af40aa2b0>

2、QuerySet

一个QuerySet表示数据库对象的一个集合,它可以迭代可以切片可以索引(不支持负数索引)
在SQL的层面上,对应的就是select语句

3、检索全部对象

直接管理器上调用all方法

In [20]: queryset=Student.objects.all()
In [21]: type(queryset)
Out[21]: django.db.models.query.QuerySet

方法all()返回一个包含所有数据的queryset对象。
可以通过打印queryset对象的query属性,来查看当前Queryet对象将要查询的sql语句

In [23]: print(queryset.query)
SELECT `t_student`.`id`, `t_student`.`name`, `t_student`.`age`, `t_student`.`phone`, `t_student`.`address`, `t_student`.`crea
te_time`, `t_student`.`channel_id` FROM `t_student` ORDER BY `t_student`.`id` ASC

In [24]: queryset
Out[24]: <QuerySet [<Student: kb>, <Student: kobe>, <Student: li>]>

a、要注意:

Queryset对象是惰性计算的,当通过管理器创建queryset的时候,并不会直接去数据库中查询,只有真正的对queryset进行计算的时候才会到数据库中查询。
什么时候?
迭代、切片、索引、打印

4、过滤

all():方法返回所有的数据,可以通过2个方法对queryset进行过滤
filter():返回新的Queryset,包含的对象满足给定的查询条件,对应where字句的正向条件
exclude():返回一个新的Queryset,包含对象不满足对给定查询参数,对应where字句的反向条件

例如:查询所有叫kobe的学生

Student.objects.filter(name='kobe')

如果是对整个查询进行操作,all可以省略

Student.objects.all().filter(name=''kobe)

同样的

Student.objects.all().exclude(name=''kobe")
Student.objects.exclude(name=''kobe")

5、查询单个对象

filter、exclude、all返回一个queryset,即使只有一个对象满足条件,这个时候queryset只包含一个元素

如果知道只有一个对象满足查询条件,可以在管理器上使用get方法,它会直接获取这个对象

Student.objects.get(pk=2)
Student.objects.get(id=2)

get方法中的条件如果过滤出多个对象会报错
如果没有这个对象也会报错

a、first方法

获取第一个对象,
对应ASC limit 1这个子句
注意:依赖于默认的排序

Student.objects.first()

b、last方法

获取最后一个对象
对应DESC LIMIT 1这个子句

Student.objects.last()

6、排序

排序是通过在queryset上调用order_by(*fields)、默认会按照主键排序,如果模型的Meta中定义了排序规则,则默认按其排序

class Meta:
	ordering=['-c_time']		模型类中加了表示默认排序

现在在student模型上进行查询,默认会使用c_time字段的desc排序

如果要清空查询集的默认排序,可以直接在查询集上调用order_by(),不用传任何参数

student.objects.order_by()

注意:

每次在Queryset上调用order_by方法都会覆盖之前的排序

In [39]: queryset
Out[39]: <QuerySet [<Student: kb>, <Student: kobe>, <Student: li>]>

查看sql语句

queryset.order_by('-name','age'):按照name降序,age升序

In [40]: q=queryset.order_by('-name','age')

In [41]: print(q.query)
SELECT `t_student`.`id`, `t_student`.`name`, `t_student`.`age`, `t_student`.`phone`, `t_student`.`address`, `t_student`.`create_time`,
`t_student`.`channel_id` FROM `t_student` ORDER BY `t_student`.`name` DESC, `t_student`.`age` ASC

7、切片

可以使用python序列切片的语法来获取部分数据,它等价于SQL的LIMIT与OFFEST子句

Student.objects.all()[:5] :获取前5条数据 等价于limit 5
Student.objects.all()[2:5] :从低3条开始取3条数据,等价于 limit 3 offset 2

前面所有的查询中,默认都是查询所有的字段。有时候只需要查询部分字段

六、选择字段

1、values

queryset.values(*fields)

返回一个queryset,这个queryset返回一个字段列表,而不是模型对象,参数fields指定select语句中,先要查询的字段。返回的字典中只会包含我们指定的字段;
如果不指定,则包含所有字段。

例如:不指定字段,返回所有的字段

Student.objects.all().values()

In [47]: q=Student.objects.all().values()


In [49]: q
Out[49]: <QuerySet [{'id': 1, 'name': 'kb', 'age': 20, 'phone': '15202629656', 'address': None, 'create_time': datetime.datetime(2023,
1, 1, 10, 41, 36, 822670, tzinfo=<UTC>), 'channel_id': None}, {'id': 2, 'name': 'kobe', 'age': 20, 'phone': None, 'address': None, 'cre
ate_time': datetime.datetime(2023, 1, 1, 15, 26, 3, 84534, tzinfo=<UTC>), 'channel_id': None}, {'id': 3, 'name': 'li', 'age': 20, 'phon
e': None, 'address': None, 'create_time': datetime.datetime(2023, 1, 1, 15, 26, 3, 84534, tzinfo=<UTC>), 'channel_id': None}]>

In [50]: q[0]
Out[50]: 
{'id': 1,
 'name': 'kb',
 'age': 20,
 'phone': '15202629656',
 'address': None,
 'create_time': datetime.datetime(2023, 1, 1, 10, 41, 36, 822670, tzinfo=<UTC>),
 'channel_id': None}

例如:指定字段,返回指定的字段

q=Student.objects.all().values('id','name')

In [52]: q=Student.objects.all().values('id','name')

In [53]: q
Out[53]: <QuerySet [{'id': 1, 'name': 'kb'}, {'id': 2, 'name': 'kobe'}, {'id': 3, 'name': 'li'}]>

In [54]: q[0]
Out[54]: {'id': 1, 'name': 'kb'}

2、value_list

queryset.value_list(*fields)

返回一个queryset,这个queryset返回一个嵌套元组的列表而不是模型对象,参数fields指定select语句中,先要查询的字段。返回的元组中只会包含我们指定的字段;
如果不指定,则包含所有字段。

例如:不指定字段,返回所有的字段

Student.objects.all().value_list()

In [3]: s=Student.objects.all()

In [7]: s2=s.values_list('name','age')

In [8]: s2
Out[8]: <QuerySet [('kb', 28), ('kobe', 20), ('li', 20), ('james', 18), ('kelai', 22), ('kd', 19), ('harden', 18), (
'curry', 22), ('ad', 19)]>

3、only

queryset.only(*fields)

返回queryset,这个queryset返回一个模型对象的列表。参数fields指定了我们想要查询的字段

注意:only一定会包含主键字段

q=Student.objects.all().only('name')

注意:
对only方法返回的模型对象,取没有指定的字段的值,django会再次去数据库中进行查询


In [3]: q=Student.objects.all().only('name')

In [4]: q
Out[4]: <QuerySet [<Student: kb>, <Student: kobe>, <Student: li>]>

In [5]: q[0]
Out[5]: <Student: kb>

In [6]: q[0].id
Out[6]: 1

In [7]: q[0].name
Out[7]: 'kb'

In [8]: q[0].age
Out[8]: 20

In [9]: print(connection.queries[-1])
{'sql': 'SELECT `t_student`.`id`, `t_student`.`age` FROM `t_student` WHERE `t_student`.`id` = 1 LIMIT
21', 'time': '0.015'}

In [10]: q
Out[10]: <QuerySet [<Student: kb>, <Student: kobe>, <Student: li>]>

In [11]: print(connection.queries[-1])
{'sql': 'SELECT `t_student`.`id`, `t_student`.`name` FROM `t_student` ORDER BY `t_student`.`id` ASC LI
MIT 21', 'time': '0.000'}

4、defer

defer(*fields)

q=Student.objects.all().defer('create_time')

defer方法中的参数fields指定了select语句中想要排除的查询字段,其他与only相同;
返回queryset,这个queryset返回一个模型对象的列表。

In [12]: q=Student.objects.all().defer('create_time')

In [13]: q
Out[13]: <QuerySet [<Student: kb>, <Student: kobe>, <Student: li>]>

In [14]: print(connection.queries[-1])
{'sql': 'SELECT `t_student`.`id`, `t_student`.`name`, `t_student`.`age`, `t_student`.`phone`, `t_stude
nt`.`address`, `t_student`.`channel_id` FROM `t_student` ORDER BY `t_student`.`id` ASC LIMIT 21', 'tim
e': '0.016'}


In [16]: q[0].create_time
Out[16]: datetime.datetime(2023, 1, 1, 10, 41, 36, 822670, tzinfo=<UTC>)

注意

only与defer返回的对象还是可以正常访问没有包含select语句中的字段,只是再次查询数据库

七、条件查询

在filter,exclude、get中可以接收参数,实现各种条件的查询

1、exact(精确匹配)、iexact(精确匹配,不区分大小写)

Student.objects.get(qq__exact=88888)
Student.objects.get(qq=88888)	简写

qq_exact=66666等价与qq=66666
默认情况下这个__exact省略
对应where语句中的相等条件

In [18]: Q=Student.objects.only('name').filter(name__iexact='KOBE')


In [20]: print(Q.query)
SELECT `t_student`.`id`, `t_student`.`name` FROM `t_student` WHERE `t_student`.`name` LIKE KOBE ORDER
BY `t_student`.`id` ASC

2、in

在一个给定的可迭代对象中,通常是一个列表,元组或者queryset

Student.objects.filter(age__in=[18,20])
对应where字句中的in

In [22]: q=Student.objects.filter(age__in=[18,20])

In [23]: print(q.query)
SELECT `t_student`.`id`, `t_student`.`name`, `t_student`.`age`, `t_student`.`phone`, `t_student`.`addr
ess`, `t_student`.`create_time`, `t_student`.`channel_id` FROM `t_student` WHERE `t_student`.`age` IN
(18, 20) ORDER BY `t_student`.`id` ASC

3、range

范围区间
对应sql中的between and

Student.objects.filter(age__range=[10,25])

4、gt、gte、lt、lte

gt:大于
gte:大于等于
lt:小于
lte:小于等于

Student.objects.filter(age__gt=18)

八、条件组合

1、AND

以下都是相同操作

Student.objects.filter(name='kobe',age=18)
Student.objects.filter(name='kobe').filter(age=18)
Student.objects.filter(name='kobe') & Student.objects.filter(age=18)

from django.db.model import Q
Student.objects.filter(Q(name='kobe') & Q(age=18))

等价于sql
where name= AND age=

2、OR

from django.db.model import Q


Student.objects.filter(name='kobe') | Student.objects.filter(age=18)
Student.objects.filter(Q(name='kobe') | Q(age=18))

等价于sql
where name= OR age=

九、聚合查询

需要导入:from django.db.models import Count,Sum,Avg,Max,Min

Count:统计数量

q8=Student.objects.aggregate(Count('id'))
print(q8)   

返回一个字典 {‘id__count’: 3}

可以指定聚合字段的值

q9=Student.objects.aggregate(count=Count('id'))
print(q9)       

返回一个字典 {‘count’: 3}

Sum:求和
Avg:求平均值
Max:求最大值
Min:求最小值

可以直接在查询集上调用count方法,会返回这个查询集的统计数量

q=Student.objects.count()

十、分组查询

一般分组会和聚合结合使用
django中需要使用values,annotate和聚合方法结合使用,

案例:
查询男女生各有多少人

Student.objects.values('sex').annotate(Count('sex'))

注意:

annotate默认使用主键进行分组
使用values时,要提前清空查询集上的order_by,不然结果是意料之外的

十一、删除对象

In [9]: s=Student.objects.get(id=1)

In [10]: s.delete()
Out[10]: (1, {'crm.Student': 1})

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/123142.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!