Django之ORM操作
目录
双下划线查询
数据准备
class Staff(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
salary = models.DecimalField(max_digits=8, decimal_places=2)
recruit_time = models.DateField(auto_now=True)
def __str__(self):
return "%s-对象" % self.name
models.Staff.objects.create(name='linda', age=22, salary=25000.00)
models.Staff.objects.create(name='rose', age=24, salary=15000.00)
models.Staff.objects.create(name='frank', age=32, salary=35000.00)
models.Staff.objects.create(name='laurence', age=24, salary=25000.00)
models.Staff.objects.create(name='steve', age=42, salary=15000.00)
models.Staff.objects.create(name='july', age=32, salary=35000.00)
models.Staff.objects.create(name='sam', age=27, salary=42000.00)
models.Staff.objects.create(name='tom', age=33, salary=28000.00)
models.Staff.objects.create(name='Simon', age=43, salary=45000.00)
具体操作
# 一、查询年龄小于等于27的员工
staff_obj = models.Staff.objects.filter(age__lte=27)
print(staff_obj)
"""
__gt 大于
__lt 小于
__gte 大于等于
__lte 小于等于
"""
# 二、查询年龄是24、32、42的员工
staff_obj = models.Staff.objects.filter(age__in=[14, 32, 42])
print(staff_obj
"""
__in 成员运算
"""
# 三、查询年龄在25到30之间的员工
staff_obj = models.Staff.objects.filter(age__range=[25, 30])
print(staff_obj)
"""
__range 范围查询
"""
# 四、查询姓名中包含字母s的员工
staff_obj = models.Staff.objects.filter(name__contains='s')
print(staff_obj) # <QuerySet [<Staff: rose-对象>, <Staff: steve-对象>, <Staff: sam-对象>]>
staff_obj = models.Staff.objects.filter(name__icontains='s')
print(staff_obj) # <QuerySet [<Staff: rose-对象>, <Staff: steve-对象>, <Staff: sam-对象>, <Staff: Simon-对象>]>
"""
__contains 区分大小写
__icontains 忽略大小写
"""
# 五、查询姓名中首字母为j的员工
staff_obj = models.Staff.objects.filter(name__startswith='j')
print(staff_obj) # <QuerySet [<Staff: july-对象>]>
# 六、查询姓名中尾字母为e的员工
staff_obj = models.Staff.objects.filter(name__endswith='e')
print(staff_obj) # <QuerySet [<Staff: rose-对象>
# 七、查询姓名中s开头m结尾的员工
staff_obj = models.Staff.objects.filter(name__regex='^s.*m$')
print(staff_obj) # <QuerySet [<Staff: sam-对象>]>
# 八、查询招聘月份是5月的员工
staff_obj = models.Staff.objects.filter(recruit_time__month=5)
print(staff_obj) # <QuerySet [<Staff: linda-对象>, <Staff: frank-对象>, <Staff: july-对象>]>
# 九、查询招聘年份是2020年的员工
staff_obj = models.Staff.objects.filter(recruit_time__year=2020)
print(staff_obj) # <QuerySet [<Staff: rose-对象>, <Staff: tom-对象>, <Staff: Simon-对象>]>
orm创建外键关系
class Staff(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
salary = models.DecimalField(max_digits=8, decimal_places=2)
recruit_time = models.DateField(auto_now=True)
def __str__(self):
return "%s-对象" % self.name
# 图书表
class Book(models.Model):
book_title = models.CharField(max_length=64, verbose_name='图书名')
book_price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name='图书价格')
publish_time = models.DateField(auto_now=True, verbose_name='出版日期')
publish = models.ForeignKey(to='Press')
authors = models.ManyToManyField(to='Author')
def __str__(self):
return "%s-图书对象" % self.book_title
# 出版社表
class Press(models.Model):
press_name = models.CharField(max_length=64, verbose_name='出版社名称')
press_addr = models.CharField(max_length=64, verbose_name='出版社地址')
def __str__(self):
return "%s-出版社对象" % self.press_name
# 作者表
class Author(models.Model):
author_name = models.CharField(max_length=64, verbose_name='作者姓名')
author_age = models.IntegerField(verbose_name='作者年龄')
author_details = models.OneToOneField(to='AuthorDetail')
def __str__(self):
return "%s-作者对象" % self.author_name
# 作者详情表
class AuthorDetail(models.Model):
author_addr = models.CharField(max_length=64, verbose_name='作者地址')
author_phone = models.BigIntegerField(verbose_name='作者联系方式')
def __str__(self):
return "%s-作者详情对象" % self.author_addr
外键字段的增删改查
# 一对多、一对一外键字段操作
增
models.Book.objects.create(book_title='初中地理', book_price=29, publish_id=1)
publish_obj = models.Press.objects.filter(pk=3).first()
models.Book.objects.create(book_title='初中生物', book_price=36, publish=publish_obj)
改
res = models.Book.objects.filter(pk=5).update(publish_id=1)
print(res)
publish_obj = models.Press.objects.filter(pk=2).first()
res = models.Book.objects.filter(pk=6).update(publish_id=publish_obj)
print(res)
# 多对多字段操作
一、第三张关系表创建数据
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.add(3, 4)
book_obj = models.Book.objects.filter(pk=3).first()
author_obj = models.Author.objects.filter(pk=5).first()
book_obj.authors.add(author_obj)
注意:括号内可以放主键值也可以放数据对象,并且都支持多个
二、第三张关系表修改数据
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.set([5])
注意:括号内必须是一个可迭代对象,元素同样支持主键值或者数据对象
三、第三张关系表删除数据
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.remove(5)
注意:括号内可以放主键值也可以放数据对象并且都支持多个
四、第三张关系表清空指定数据
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.clear()
注意:括号内无需传值,直接清空当前表在第三张关系表中的绑定记录
正反向的概念
核心在于当前数据对象是否含有外键字段:有则是正向,没有则是反向
正向
eg:
由书籍查询出版社,外键字段在书籍表中,那么书查出版社就是'正向'
由书籍查询作者,外键字段在书籍表中,那么书查作者就是'正向'
由作者查询作者详情,外键字段在作者表中,那么也是'正向'
反向
eg:
由出版社查询书籍 外键字段不在出版社表 那么出版社查书就是'反向'
多表查询
基于对象的跨表查询
基于对象的跨表查询本质就是子查询即分步操作即可
# 查询初中生物书籍对应的出版社
# book_obj = models.Book.objects.filter(book_title='初中生物').first()
# res = book_obj.publish
# print(res) # 西南师范大学出版社-出版社对象
# 查询小学英语对应的作者
# book_obj = models.Book.objects.filter(book_title='小学英语').first()
# res = book_obj.authors.all()
# print(res) # <QuerySet [<Author: david-作者对象>, <Author: 李华-作者对象>]>
# 查询作者david的详情信息
# author_obj = models.Author.objects.filter(author_name='david').first()
# res = author_obj.author_details
# print(res) # 北京-作者详情对象
# 查询四川大学出版社出版的书籍
# publish_obj = models.Press.objects.filter(press_name='四川大学出版社').first()
# res = publish_obj.book_set.all()
# print(res) # <QuerySet [<Book: 初中英语-图书对象>, <Book: 初中数学-图书对象>, <Book: 科学世界-图书对象>]>
# 查询朱巍编写的书籍
# author_obj = models.Author.objects.filter(author_name='朱巍').first()
# res = author_obj.book_set.all()
# print(res) # <QuerySet [<Book: 地理探索-图书对象>, <Book: 初中生物-图书对象>]>
# 查询地址在杭州的作者
# author_detail_obj = models.AuthorDetail.objects.filter(author_addr='杭州').first()
# res = author_detail_obj.author
# print(res) # 李华-作者对象
基于双下划线的跨表查询
基于双下划线的跨表查询本质就是联表操作
# 查询科学世界书籍对应的出版社名称
# res = models.Press.objects.filter(book__book_title='科学世界')
# print(res) # <QuerySet [<Press: 四川大学出版社-出版社对象>]>
# res = models.Press.objects.filter(book__book_title='科学世界').values('press_name')
# print(res) # <QuerySet [{'press_name': '四川大学出版社'}]>
# 查询地理探索对应的作者姓名和年龄
# res = models.Author.objects.filter(book__book_title='地理探索').values('author_name', 'author_age')
# print(res) # <QuerySet [{'author_name': '朱巍', 'author_age': 32}]>
# 查询作者david的联系方式和地址
# res = models.AuthorDetail.objects.filter(author__author_name='david').values('author_phone', 'author_addr')
# print(res) # <QuerySet [{'author_phone': 19940405858, 'author_addr': '北京'}]>
# 查询西南师范大学出版社出版的书籍名称和价格
# res = models.Book.objects.filter(publish__press_name='西南师范大学出版社').values('book_title', 'book_price')
# print(res) # <QuerySet [{'book_title': '小学英语', 'book_price': Decimal('40.00')}, {'book_title': '初中生物', 'book_price': Decimal('36.00')}]>
# 查询王涛编写的书籍名称和日期
# res = models.Book.objects.filter(authors__author_name='王涛').values('book_title', 'publish_time')
# print(res) # <QuerySet [{'book_title': '科学世界', 'publish_time': datetime.date(2020, 8, 12)}, {'book_title': '初中生物', 'publish_time': datetime.date(2022, 5, 17)}]>
# 查询地址在北京的作者的姓名和年龄
# res = models.Author.objects.filter(author_details__author_addr='北京').values('author_name', 'author_age')
# print(res) # <QuerySet [{'author_name': 'david', 'author_age': 24}]>
双下线查询扩展
基于双下划线的跨表查询的结果也可以是完整的数据对象
# 查询科学世界书籍对应的出版社名称
# res = models.Press.objects.filter(book__book_title='科学世界').first()
# print(res) # 四川大学出版社-出版社对象
# 查询地理探索对应的作者姓名和年龄
# res = models.Author.objects.filter(book__book_title='地理探索').values('author_name', 'author_age')
# print(res) # <QuerySet [{'author_name': '朱巍', 'author_age': 32}, {'author_name': '李华', 'author_age': 26}]>
# 查询作者david的联系方式和地址
# res = models.AuthorDetail.objects.filter(author__author_name='david').values('author_phone', 'author_addr')
# print(res) # <QuerySet [{'author_phone': 19940405858, 'author_addr': '北京'}]>
# 查询西南师范大学出版社出版的书籍名称和价格
res = models.Book.objects.filter(publish__press_name='西南师范大学出版社').values('book_title', 'book_price')
print(res) # <QuerySet [{'book_title': '小学英语', 'book_price': Decimal('40.00')}, {'book_title': '初中生物', 'book_price': Decimal('36.00')}]>
# 查询王涛编写的书籍名称和日期
# res = models.Book.objects.filter(authors__author_name='王涛').values('book_title', 'publish_time')
# print(res) # <QuerySet [{'book_title': '科学世界', 'publish_time': datetime.date(2020, 8, 12)}, {'book_title': '初中生物', 'publish_time': datetime.date(2022, 5, 17)}]>
# 查询地址在北京的作者的姓名和年龄
# res = models.Author.objects.filter(author_details__author_addr='北京').values('author_name', 'author_age')
# print(res) # <QuerySet [{'author_name': 'david', 'author_age': 24}]>
# 连续跨表操作
# 查询小学英语对应的作者的地址
res = models.AuthorDetail.objects.filter(author__book__book_title='小学英语').values('author_addr')
print(res) # <QuerySet [{'author_addr': '北京'}, {'author_addr': '杭州'}]>
# 获取多张表里面的字段数据
# 查询初中数学对应的作者的地址和出版社名称
res = models.AuthorDetail.objects.filter(author__book__book_title='初中数学').values('author_addr', 'author__book__publish__press_name')
print(res) # <QuerySet [{'author_addr': '北京', 'author__book__publish__press_name': '四川大学出版社'}]>
如何查看SQL语句
方式1:句点符加query查看
如果结果集对象是queryset可以点query查看
方式2:配置文件固定配置
只要执行了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 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?