正反向进阶操作
# 正向查询
1.查询电话号码问1234的学校名称
# res = models.School.objects.filter(schoolinfo_fo__phone='1234').values('name')
# print(res) # <QuerySet [{'name': '华清大学'}]>
2.查询学校名称为南芜大学的学生姓名及年龄
# res = models.Student.objects.filter(school_fo__name='南芜大学').values('name', 'age')
# print(res) # <QuerySet [{'name': 'kevin', 'age': 20}]>
3.查询lili同学的老师姓名及年龄
res = models.Teacher.objects.filter(student_fo__name='lili').values('name', 'age')
print(res) # <QuerySet [{'name': 'lili', 'age': 25}, {'name': 'jason', 'age': 28}]>
# 反向查询
4.查询主键值为1的学校对应的学校信息 - -一对一
# res = models.SchoolInfo.objects.filter(school__pk=1).values('phone', 'date_time')
# print(res) # <QuerySet [{'phone': '4321', 'date_time': datetime.date(2022, 9, 5)}]> 学校字段不加匹配不加括号
5.查询主键为1的学生对应的学校(学生 ---学校)--一对多
# res = models.School.objects.filter(student__pk=1).values('name')
# print(res) # <QuerySet [{'name': '华清大学'}]>
6.查询老师主键为1教授的学生姓名及年龄
# res = models.Student.objects.filter(teacher__pk=1).values('name', 'age')
# print(res) # <QuerySet [{'name': 'lili', 'age': 18}, {'name': 'kevin', 'age': 20}]>
聚合查询
1.通过聚合函数对数据进行查询(遵循正反向查询规律)关键字:aggregate
from django.db.models import Max, Min, Count, Sum, Avg
1.查询学生年龄最小的学生姓名及年龄
# age_info = models.Student.objects.aggregate(min_age=Min('age'))
# print(age_info) # {'min_age': 18}
2.查询学校数量
# student_num = models.School.objects.aggregate(num=Count('name'))
# print(student_num) # {'num': 3}
3.查询lili同学的成绩平均值
# result = models.Student.objects.filter(name='lili').aggregate(result_avg=Avg('result'))
# print(result) # {'result_avg': 62.8}
4.查询lili同学总共学习了几门课程
# course = models.Student.objects.filter(name='lili').aggregate(course_sum=Sum('course'))
print(course) # {'course_sum': 3}
分组查询
1.filter角色:在分组前使用相当于mysql中的where筛选 在分组后使用相当于mysql中的having过滤
2.分组关键字:annotate
1.查询各学校中里面的学生人数
# student_num = models.School.objects.annotate(student_num=Count('student__pk')).values('name', 'student_num')
# print(student_num) # <QuerySet [{'name': '南芜大学', 'student_num': 1}, {'name': '华清大学', 'student_num': 2}, {'name': '西南大学', 'student_num': 1}]>
2.统计学生学习的课程数量大于等于2门的学生姓名及课程数量
course_num = models.Student.objects.annotate(course_num=Sum('course')).filter(course_num__gt=2).values('name', 'course_num')
print(course_num) # <QuerySet [{'name': 'kevin', 'course_num': 3}, {'name': 'tony', 'course_num': 4}]>
F查询
1.F查询涉及查询字段都来源于表中字段非固定数据
1.查询学生lili的地址前加中国
from django.db.models import F, Value
from django.db.models.functions import Concat
models.Student.objects.filter(name='lili').update(addr=Concat(F('addr'), Value('中国')))
Q查询
1.Q可以改变filter内多个条件之间的逻辑关系
1. 查询主键为1的学校及学生主键为1的学校
# res = models.Student.objects.filter(Q(pk=1), Q(student__pk=1)) # ,and关系
# res = models.Student.objects.filter(Q(pk=1) | Q(student__pk=1)) # |or关系
# res = models.School.objects.filter(Q(pk=1) |~ Q(student__pk=1)) # ~not关系
2.将查询条件字段改为字符串(用户输入)
obj = Q()
obj.connector = 'or' # 默认是and的关系
obj.children.append(('pk', 1))
obj.children.append(('school_fo_id', 3))
obj.children.append(('school_fo_id', 2))
res = models.Student.objects.filter(obj)
print(res)
ORM查询优化
1.减少数据库的查询(django orm默认是惰性查询 真正需要时才会执行代码)
2.django orm自带limit分页 减少数据库及服务端的压力
3.only与defer(会将括号内填写的字段封装成一个个数据对象)
3.1 only:对象在点击括号中出现的字段 不会再走数据库查询
对象点括号内没有的字段时 每次都会走数据库查询
res = models.Student.objects.only('name', 'age')
for obj in res:
print(obj.name)
print(obj.age)
print(obj.addr)
print(res.query)
3.2 defer:数据对象点击括号中出现的字段 每次都会走数据库查询
对象点击括号内不存在的字段 不会走数据库查询
res = models.Student.objects.defer('name')
for obj in res:
print(obj.name)
print(obj.age)
print(obj.addr)
print(res.query)
4.select_related与prefetch_related
4.1 select_related:括号内只能接受外键字段(一对一 一对多)自动连表
数据对象点击表中数据的时候不会走数据库查询
res = models.Student.objects.all()
for obj in res:
print(obj.school_fo.name)
print(res.query) # 每次都会走数据库查询
res = models.Student.objects.select_related('school_fo') # 连表查询INNER JOIN
for obj in res:
print(obj.school_fo.name)
4.2 prefetch_related:底层是子查询 将查询之后的结果一次性封装到数据对象中
res = models.Student.objects.prefetch_related('school_fo') # 子查询
for obj in res:
print(obj.school_fo.name)
事务操作
事务:ACID
事务隔离级别:脏读 幻读 不可重复读 ...
原生SQL: start transaction\rollback\commit\savepoint
from django.db import transaction
try:
with transaction.atomic():
pass # 多条ORM语句
except Exception as e:
print(e)
ORM常见字段类型
1.字段类型
字段类型 | 作用 |
---|---|
AutoField() | 主键自增 |
CharField() | varchar(255) |
IntegerField() | 整数 |
BigIntegerField() | 整数 |
DateField() | 年月日 |
DateTimeField() | 年月日 时分秒 |
DecimalField() | 小数精确度最高 |
EmailField() | 电子邮箱格式 |
BooleanField() | 传布尔值返回数字0或1 |
TextField() | 存储大段文本 |
FileField() | 储存文件数据 自动指定存储位置 字段的具体路径 |
ForeignKey() | 外键一对多 |
OneToOneField() | 外键一对一 |
ManyToManyField() | 外键多对多 |
2.自定义字段类型
class MyCharField(models.Field):
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super().__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
return 'char(%s)' % self.max_length
info = MyCharField(max_length=32)
ORM常见参数
参数 | 作用 |
---|---|
max_length | 最大长度 |
verboses_name | 起别名 |
auto_now | 每次修改数据自动刷新时间 |
auto_now_add | 第一次修改数据刷新时间 |
null | 空 |
default | 默认值 |
max_digits | 最大个数 |
decimal_places | 小数个数 |
unique=True | 唯一 |
db_index=True | 索引 |
choices | 数据库中存放数字 节省空间 在models.py中进行数字与数据绑定 |
to | 设置关联表 |
to_field | 设置关联的字段 |
related_name | 相关对象到此对象的关系的名称 |
on_delete | models.CASCADE 级联删除(表中一条关联数据被删除 所有关联数据删除) |
models.SET_NULL 当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null 定义外键时要写明允许为空 | |
models.PROTECT 当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除 | |
models.SET_DEFAULT 当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值 | |
models.SET() 当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数 | |
models.DO_NOTHING 数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似 |
多对多创建方式
1.自动创建
student_fo = models.ManyToManyField(to='Student')
优点:第三张表自动创建
缺点:第三张表扩展性差
2.手动创建
class Teacher(models.Model):
pass
class Student(models.Model):
pass
class Teacher2Student(models.Model):
student_id = models.ForeignKey(to="Teacher")
teacher_id = models.ForeignKey(to="Student")
优点:第三张表扩展性强
缺点:无法使用正反向查询以及多对多四个方法
3.半自动创建
class Teacher(models.Model):
student_fo = models.ManyToManyField(to='Student',
through='Teacher2Student'
through_fields=('teacher_id','student_id')
)
class Student(models.Model):
pass
class Teacher2Student(models.Model):
student_id = models.ForeignKey(to="Teacher")
teacher_id = models.ForeignKey(to="Student")
优点:扩展性强并且支持正反向查询
缺点:无法使用多对多四个方法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理