文章目录
一、数据库数据操作
一旦创建数据模型后,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中定义了排序规则,则默认按其排序
classMeta:
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})
版权归原作者 敲代码敲到头发茂密 所有, 如有侵权,请联系我们删除。