Django基础篇:ORM双下划线、ORM创建外键关系、外键增删改查、正反向多表查询
2022.5.17 django使用ORM操作数据库进阶知识
-
神奇的双下划线查询
-
orm创建外键关系
-
外键字段的增删改查
-
正反向的概念
-
多表查询
一、神奇的双下划线查询(ORM操作数据库语法)
1、判断大小
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
__gt 大于
__lt 小于
__gte 大于等于
__lte 小于等于
eg:
查询年龄大于20的用户
res = models.User.objects.filter(age__gt=20) # 等号仅作为赋值运算
2、成员运算
复制代码
- 1
- 2
- 3
- 4
- 5
__in 是否含有
eg:
查询年龄是18、22、25的用户
res = models.User.objects.filter(age__in=[18,22,25])
3、范围查询
复制代码
- 1
- 2
- 3
- 4
- 5
__range 范围查询(顾头顾尾)
eg:
查询年龄在18到26之间的用户
res = models.User.objects.filter(age__range=[18,26]) # 包含18和26
4、字段包含某字符
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
__contains 区分大小写
__icontains 忽略大小写
eg:
查询姓名中包含字母j和J的用户
res = models.User.objects.filter(name__contains='j')
查询姓名中包含字母j的用户
res = models.User.objects.filter(name__icontains='j')
5、按时间查询
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
__year 按照年份筛选数据
__month 按照月份筛选数据
...
eg:
查询年份是22年的数据
res = models.User.objects.filter(op_time__year=2022)
查询月份是5月的数据
res = models.User.objects.filter(op_time_month=5)
6、其他方法补充
复制代码
- 1
- 2
- 3
__startwith 以**开头
__endswith 以**结尾
__regex 正则
二、orm创建外键关系
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
# 创建以下几张表
图书表
出版社表
作者表
作者详情表
# 关系分析
书与出版社 >>> 一对多关系
外键名 = models.ForeignKey(to='表名')
书与作者 >>> 多对多关系
外键名 = models.ManyToManyField(to='表名')
作者与详情 >>> 一对一关系
外键名 = models.OneToOneField(to='表名')
ps:三个关键字里面的参数
to用于指定跟哪张表有关系 自动关联主键
to_field\to_fields 也可以自己指定关联字段
# 字段位置
一对多关系 >>> 外键字段建在多的一方
多对多关系 >>> 外键字段建在其中一个中,第三张关系自动创建
一对一关系 >>> 外键字段建在任意一方都可以,但是推荐建在查询频率较高的表中
# ManyToManyField不会在表中创建实际的字段,而是告诉django orm自动创建第三张关系表;
# ForeignKey、OneToOneField会在字段的后面自动添加_id后缀,如果你在定义模型类的时候自己添加了该后缀那么迁移的时候还会再次添加_id_id,所以不要自己加_id后缀;
三、外键字段的增删改查
1、一对一、一对多关系外键字段操作
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
# 新增字段
方式1:直接指定外键值
models.Book.objects.create(title='聊斋志异',price='16895.63',publish_id=1) # 直接指定外键的值
方式2:指定外键对象
publish_obj = models.Publish.objects.filter(pk=1).first() # 先获取子表中的对应一条数据对象
models.Book.objects.create(title='聊斋志异',price='16895.63',publish=publish_obj) # 将对象赋值给publish字段即可
# 修改字段
方式1:
...update(publish_id=3)
方式2:
...update(publish=publish_obj)
2、多对多字段操作(增删改)
通过创建关系字段的那张表获取到的对象,即可修改指定对应的关系;
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
先获取创建关系的表中的一个对象:
book_obj = models.Book.objects.filter(pk=1).first()
然后就可以对这个对象进行增删改:
1.第三张关系表创建数据
给某对象添加指定关系:
book_obj.authors.add(1,2...)
# 括号内可以放主键值也可以放数据对象,并且都支持多个;
2.第三张关系表修改数据
book_obj.authors.set([1,2...])
括号内必须是一个可迭代对象,元素同样支持主键值或者数据对象;
3.第三张关系表删除数据
book_obj.authors.remove(1,2...)
括号内可以放主键值也可以放数据对象,并且都支持多个;
4.第三张关系表清空指定数据
book_obj.authors.clear()
括号内无需传值,直接清空当前表在第三张关系表中的绑定记录;
四、正反向的概念
核心在于当前数据对象是否含有外键字段,有则是正向,没有则是反向;
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
# 正向
eg:
由书籍查询出版社 外键字段在书籍表中 那么书查出版社就是'正向'
由书籍查询作者 外键字段在书籍表中 那么书查作者就是'正向'
由作者查询作者详情 外键字段在作者表中 那么也是'正向'
# 反向
eg:
由出版社查询书籍 外键字段不在出版社表 那么出版社查书就是'反向'
...
"""
查询口诀
正向查询按外键字段名
反向查询按表名小写
"""
五、多表查询
复习MySQL多表查询:
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
"""
MySQL多表查询思路
子查询
将SQL语句用括号括起来当做条件使用
连表操作
inner join\left join\right join\union
django orm本质还是使用的上述两种方法
子查询>>>:基于对象的跨表查询
连表操作>>>:基于双下划线的跨表查询
"""
1、基于对象的跨表查询
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
"""基于对象的跨表查询本质就是子查询即分步操作即可"""
先获取对象
obj = models.表名.objects.filter(条件).first()
再跨表查询
obj.外键名/obj.外键名.all()/obj.外键名_set.all()
案例:
# 1.查询数据分析书籍对应的出版社
# 先获取书籍对象
book_obj = models.Book.objects.filter(title='数据分析').first()
# 再使用跨表查询
res = book_obj.publish
print(res) # 出版社对象:北方出版社
# 2.查询python全栈开发对应的作者
# 先获取书籍对象
book_obj = models.Book.objects.filter(title='python全栈开发').first()
# 再使用跨表查询
res = book_obj.authors # app01.Author.None
res = book_obj.authors.all()
print(res) # <QuerySet [<Author: 作者对象:jason>, <Author: 作者对象:jerry>]>
# 3.查询作者jason的详情信息
# 先获取jason作者对象
author_obj = models.Author.objects.filter(name='jason').first()
# 再使用跨表查询
res = author_obj.author_detail
print(res) # 作者详情对象:芜湖
# 4.查询东方出版社出版的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
res = publish_obj.book_set # app01.Book.None
res = publish_obj.book_set.all()
print(res) # <QuerySet [<Book: 书籍对象:linux云计算>, <Book: 书籍对象:聊斋志异>]>
# 5.查询jason编写的书籍
author_obj = models.Author.objects.filter(name='jason').first()
res = author_obj.book_set # app01.Book.None
res = author_obj.book_set.all()
print(res) # <QuerySet [<Book: 书籍对象:golang高并发>, <Book: 书籍对象:python全栈开发>]>
# 6.查询电话是110的作者
author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
res = author_detail_obj.author
print(res) # 作者对象:jason
2、基于双下划线的跨表查询
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
"""基于双下划线的跨表查询本质就是连表操作"""
models.表名.objects.filter(条件).values('字段名', '外键名__外键字段')
查询数据分析书籍对应的价格和出版日期
models.Book.objects.filter(title='数据分析').values('price','publish_time')
'''手上有什么条件就先拿models点该条件对应的表名'''
案例:
# 1.查询数据分析书籍对应的出版社名称
res = models.Book.objects.filter(title='数据分析').values('publish__name', 'publish__addr')
print(res) # <QuerySet [{'publish__name': '北方出版社', 'publish__addr': '北京'}]>
# 2.查询python全栈开发对应的作者姓名和年龄
res = models.Book.objects.filter(title='python全栈开发').values('authors__name','authors__age')
print(res) # <QuerySet [{'authors__name': 'jason', 'authors__age': 18}, {'authors__name': 'jerry', 'authors__age': 29}]>
# 3.查询作者jason的手机号和地址
res = models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr')
print(res) # <QuerySet [{'author_detail__phone': 110, 'author_detail__addr': '芜湖'}]>
# 4.查询东方出版社出版的书籍名称和价格
res = models.Publish.objects.filter(name='东方出版社').values('book__title','book__price')
print(res) # <QuerySet [{'book__title': 'linux云计算', 'book__price': Decimal('24888.44')}, {'book__title': '聊斋志异', 'book__price': Decimal('16987.22')}]>
# 5.查询jason编写的书籍名称和日期
res = models.Author.objects.filter(name='jason').values('book__title', 'book__publish_time')
print(res) # <QuerySet [{'book__title': 'golang高并发', 'book__publish_time': datetime.date(2022, 6, 7)}, {'book__title': 'python全栈开发', 'book__publish_time': datetime.date(2022, 2, 28)}]>
# 6.查询电话是110的作者的姓名和年龄
res = models.AuthorDetail.objects.filter(phone=110).values('author__name','author__age')
print(res) # <QuerySet [{'author__name': 'jason', 'author__age': 18}]>
3、双下线查询扩展(进阶拓展)
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
"""基于双下划线的跨表查询的结果也可以是完整的数据对象"""
思考:如何不使用models点当前的表,直接models点所需要数据的表,来获取对应当前表的数据?
直接models点所需数据对应的表,筛选条件使用关联外键的表的数据,然后获取对应的所需数据的values
案例分析:
# 1.查询数据分析书籍对应的出版社名称
res = models.Publish.objects.filter(book__title='数据分析')
print(res) # <QuerySet [<Publish: 出版社对象:北方出版社>]>
res = models.Publish.objects.filter(book__title='数据分析').values('name')
print(res) # <QuerySet [{'name': '北方出版社'}]>
# 2.查询python全栈开发对应的作者姓名和年龄
res = models.Author.objects.filter(book__title='python全栈开发').values('name','age')
print(res) # <QuerySet [{'name': 'jason', 'age': 18}, {'name': 'jerry', 'age': 29}]>
# 3.查询作者jason的手机号和地址
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','addr')
print(res) # <QuerySet [{'phone': 110, 'addr': '芜湖'}]>
# 4.查询东方出版社出版的书籍名称和价格
res = models.Book.objects.filter(publish__name='东方出版社').values('title','price')
print(res) # <QuerySet [{'title': 'linux云计算', 'price': Decimal('24888.44')}, {'title': '聊斋志异', 'price': Decimal('16987.22')}]>
# 5.查询jason编写的书籍名称和日期
res = models.Book.objects.filter(authors__name='jason').values('title','publish_time')
print(res) # <QuerySet [{'title': 'golang高并发', 'publish_time': datetime.date(2022, 6, 7)}, {'title': 'python全栈开发', 'publish_time': datetime.date(2022, 2, 28)}]>
# 6.查询电话是110的作者的姓名和年龄
res = models.Author.objects.filter(author_detail__phone=110).values('name','age')
print(res) # <QuerySet [{'name': 'jason', 'age': 18}]>
# 连续跨表操作
# 查询python全栈开发对应的作者的手机号
res = models.Book.objects.filter(title='python全栈开发').values('authors__author_detail__phone')
print(res) # <QuerySet [{'authors__author_detail__phone': 110}, {'authors__author_detail__phone': 140}]>
res1 = models.AuthorDetail.objects.filter(author__book__title='python全栈开发').values('phone')
print(res1) # <QuerySet [{'phone': 110}, {'phone': 140}]>
"""
可能出现的不是疑问的疑问:如何获取多张表里面的字段数据?
res = models.Book.objects.filter(title='python全栈开发').values('authors__author_detail__phone','authors__name','title')
print(res)
"""
补充:如何查看SQL语句?
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
方式1:如果结果集对象是queryset 那么可以直接点query查看
方式2:配置文件固定配置,SQL语句自动打印的配置文件
适用面更广,只要执行了orm操作,都会打印内部SQL语句;
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?