day7-django数据库操作
数据库操作
为了方便调试,django开发了一个命令shell,通过python manage.py shell 进入解释器,它会自动的导入当前项目的所有环境变量
注意:要安装ipython方便调试
创建对象
模型类代表数据表,模型实例代表数据表中的一条记录
所有创建一个对象,用关键字初始化,然后调用save()就是保存到数据库
1 from crm.models import Student 2 s = Student(name='xinlan', age=18) 3 s.save()
这里幕后,django执行INSERT
SQL语句。Django在你显示的调用save()
的时候才会操作数据库。
更行对象
要将修改保存至数据库中某个已存在的对象,使用save()
s.age = 19
s.save()
指定要更行的字段
默认情况下save方法执行update的时候会全字段更新,效率不高
可以传递一个字段列表给关键字参数update_fields,那么只有列表中指定的字段才会被更新,当只更新一个对象上的一个或几个字段的时候,可以使用这个字段。有轻微的性能优势
s.age=19 s.save(update_fields=["age"]) # 指定只更新age字段
一次更新多个字段
想要一次更新多个字段,需要再查询集上调用updae,例如
Student.objects.all()update(sex=0) --------慎用
注意:update不会调用对象上的save()方法,如果对象多个对象,又想执行save,可以迭代每个对象,分别调用save,update是一条语句
什么时候是插入,什么时候是更新
当对象有pk属性的时候,这时调用save就是更新,否则就是插入
查询对象
管理器
要从数据库去检索对象,需要通过模型类的Manage构建一个QuerySet。每个模型至少有一个管理器,默认名称是objects,例如:
Student.objects
注意:通过模型对象不能直接访问管理器
QuerySet(查询集)
一个QuertSet代表来自数据库中对象的一个集合,它可以被迭代,切片,可以正整数索引(不支持负索引),可以通过list转换为列表。在sql层面对应的是一条select语句
检索全部对象
在管理器上调用all方法
s=Student.objects.all()
方法all()返回一个包含数据库表所有对象的QuerySet对象
过滤
在管理器上调用下面两个方法,可以对queryset进行过滤
filter(**kwargs)
返回一个新的queryset,包含的对象满足给定的查询参数
exclude(**kwargs)
返回一个新的queryset,包含的对象不满足给定的查询参数
例如:
查询名字叫tom的
qs = Student.objects.filter(name="tom")
第二种写法:qs = Student.objects.filter(name="tom")
查询名字不叫tom的
qs = Student.objects.exclude(name="tom")
检索单个数据
这些方法都是返回queryset,即使只有一个对象,也是返回queryset。如果要获取单个好需要进行索引
get(**kwargs)
获取一个对象,如果对象不存在会报错,存在多个对象也会保存。一般用pk这个条件
s = Student.objects.get(pk=1)
s = Student.objects.get(name="tom")
first()
Student.objects.first()
返回查询集的第一个对象
last()
Student.objects.last()
返回查询集的最后一个对象
排序
默认情况下,django会按照主键进行排序,可以通过在模型的Meta属性中定义默认排序
class Student(models.Model): # 必须继承 ...... class Meta: ...... ordering = ["age"] # 根据年龄排序从小到大 [-age]从大到小
模型中的排序是默认的,在查询集上可以主动调用排序
order by(*fields)
根据给定的字段进行排序,字段名字前加负号表示desc,
Student.objects.all().order_by("-age","name")
查询年龄最小的学生
StudentStudent.objects.all().order_by("age").first()
切片
使用序列的切片语法来获取查询集的部分数据,它等价于sql中的limit,offset子句
获取前5条
StudentStudent.objects.all()[:5]
获取3,4条数据
StudentStudent.objects.all()[2:5] # 等价于limit 3 offset 2
queryset惰性计算
查询集为了多次过滤,需要提高性能,它是惰性计算,也就意味着只是取值的时候才回去数据库中查询数据
- 迭代queryset
- 对queryset进行索引
- 在命令行输出
注:一个查询集在进行上面的操作时,才会去数据库获取数据
选择字段查询
在上面的查询中,都是查询所有的字段
- values(fields):
返回一个queryset,这个queryset返回的是字典列表,而不是数据对象,参数fields指定在select语句中想要查询的字段,返回的字段会包含指定的字段,如果不指定字段,会返回所有字段
Student.objects.values("name")
- only(fields):
返回一个queryset,这个queryset返回的是对象列表。fields指定我们在select语句中想要查询的字段,即使不指定主键字段,对象中也一定包含主键字段
Student.objects.only("name")
- defer(fields):
它的机制和only相同,只是筛选逻辑相反,参数fields指定在select语句中想要排除的字段,对象中也一定会包含主键
Student.objects.defer("name")
条件查询
在filter、exclude、get中可以接受参数实现各种比较条件的查询
- exact:精确匹配,在字段后面加 __exact
Student.objects.filter(name__exact="tom") Student.objects.filter(namet="tom") # exact一般会省略掉
- iexact:不区分大小写
Student.objects.filter(level__iexact="A") # 匹配level为a和A的学生
- gt:大于
Student.objects.filter(age__gt=18) # 查询年龄大于18的学生
- lt:大于
Student.objects.filter(age__lt=18) # 查询年龄小于18的学生
- gte:大于等于
Student.objects.filter(age__gte=18) # 查询年龄大于等于18的学生
- lte:大于等于
Student.objects.filter(age__lte=18) # 查询年龄小于等于18的学生
- range:范围
Student.objects.filter(age__range=(18,30)) # 查询年龄大于18小于30的学生,等价于between and
- in:离散范围
Studetn.objects.filter(age__in=(18,20,22,30)) # 查询年龄在18,20,22,30范围内的学生
注:更多内容见官方文档 https://docs.djangoproject.com/zh-hans/3.2/ref/models/querysets/#field-lookups
条件组合
- AND
使用sql AND操作符将两个QuerySet组合起来
# 查询18岁以上的男生 # 第一种 Student.objects.filter(sex=1,age__gt=18) # 第二种 Student.objects.filter(sex=1) & Student.objects.filter(age__gt=18) # 第三种 from django.db.models from Q Student.objects.filter(Q(sex=1)) & Q(age__gt=18)
- OR
使用sql OR操作符将两个QuerySet组合起来
# 查询大于18岁,或者小于13岁的学生 # 第一种 Student.objects.filter(age__gt=18) | Student.objects.filter(age__lt=13) # 第二种 from django.db.models import Q Student.objects.filter(Q(age__gt=18)) | Q (age__lt=13)
聚合查询
- count
在查询集上直接使用count方法,会返回记录的条数
# 查询女生的人数 Student.objects.filter(sex=0).count()
- avg
使用平均值函数,需要在查询集上调用aggregate方法
# 计算学生的平均年龄 from django.db.models import Avg Student.objects.all().aggregate(Avg("age")) # 输出:{'age__avg': 19.0} Student.objects.all().aggregate(ageavg=Avg("age")) # 通过关键字指定字段名 # 输出:{'ageavg':19.0}
- max
from django.db.models import Max # 查询年龄最大的学生 Student.objects.all().aggregate(Max('age')) # 输出:{'age_max':19}
- min
from django.db.models import Min # 查询年龄最小的学生 Student.objects.all().aggregate(Min('age'))
- sum
from django.db.models import Sum # 查询所有人年龄的总和 Student.objects.all().aggregate(Sum('age'))
分组
- annotate
上面的聚合是不分组聚合,要在每个对象上增加聚合字段,需要利用分组
按字段分组需要用values和annotate配合
# 查询男女生各有多少人 Student.objects.values('sex').annotate(Count('sex')) Student.objects.values('sex').annotate(Count('sex')).order_by() # 查询男女生的平均年龄 Student.objects.values("sex").annotate(Avg("age")).order_by() # 查询男女生年龄最大的人 Student.objects.values("sex").annotate(Max("age")).order_by()
注意:排序会有影响,如果模型有了排序后,需要在命令后面加上order_by()去掉排序