Django-ORM增删查改全部讲解(一文全通),高级查询,F/Q对象,单/多条件查询,联合查询,和/或查询,聚合查询函数,字段之间对比查询,主表从表查询,外键约束查询,复杂条件查询,正则查询

Django-ORM基本增删查改

建议阅读顺序: 增加-查询-更新-删除

建议看右边的文章目录,根据需求看!!!

项目基本结构及字段

数据表:

  1. BookInfo表(书籍信息表)
  2. RoleInfo表(人物信息表)

Models.py中表的定义

from django.db import models


# Create your models here.

class Book(models.Model):
    class Meta:
        db_table = 'BookInfo'
        verbose_name = '图书信息'

    name = models.CharField(max_length=128, blank=False, verbose_name='书名')
    pub_time = models.DateField(verbose_name='发布时间')
    author = models.CharField(max_length=128, blank=False, default='未知', verbose_name='作者名')
    sale = models.IntegerField(blank=False, default=0, null=False)
    comment_num = models.IntegerField(blank=False, default=0, null=False)

class Role(models.Model):
    class Meta:
        db_table = 'RoleInfo'
        verbose_name = '角色信息'

    name = models.CharField(max_length=128, blank=False, verbose_name='角色名')
    book = models.ForeignKey('Book', on_delete=models.CASCADE, verbose_name='所属书籍') # 外键约束
    is_good = models.BooleanField(blank=False, verbose_name='是否为好角色')

BookInfo表基本数据
在这里插入图片描述

RoleInfo表基本数据

在这里插入图片描述

必看: Django Shell的使用


Django Shell 是集成于项目的命令提示行,便于我们对ORM进行数据测试

# 使用方法

cd 项目根目录(manage.py所在目录)
python ./manage.py shell

在这里插入图片描述

长得其实就是Python命令提示行

进入Django Shell后,我们可以先导入我们定义好的Model类,进行相关的调试

from Book.models import *
# 测试查询
Book.objects.get(id__exact=21)
# 返回结果
# 这样我们不用进行视图的编写,就可以调试ORM

在这里插入图片描述

1. 增加数据

1.1 使用objects.create 新增数据

objects是models子类的属性

from Book.models import * # 引用Models中的所有ORM表结构

增加数据

Book.objects.create(
    name='create新增数据',
    pub_time='2001-11-25',
    author='Ruan',
)
# 该方法直接调用models对象增加数据,直接加入到数据库.

1.2 使用实例化对象.save() 保存数据

x = Book(
    name="我的简史",
    pub_time="2012-04-25",
    author="霍金",
)
type(x) -> Book.models.Book 即Book类的实例对象
x.save() #必须调用.save()才会写入数据库

2. 更新数据 (建议先看查询数据)

更新数据=SQL中的UPDATE,Django进行了封装,用法简单

更新数据需要使用models对象的update()进行更新

2.1 update更新

####  语法规则:
QuerySet|obj.filter(条件).update('字段1'=新值,"字段2"=新值)

#### 需求:
#### 	将所有author = 霍金的行的 author字段
objs = Book.objects.filter(author='霍金') # 所有=霍金的对象
-> QuerySet 
objs.update(
    author='史蒂夫 · 霍金'
) # 更新所有数据

Tips:
update必须是一个QuerySet,也就是说obj.get的数据是不能update的

2.2 修改后save

通过对model对象的值进行修改,再通过save保存,也是常见的更新数据方式

obj = Book.objects.get(id=26) #根据id查询只有一个,直接get即可
obj.author='狗狗'
obj.save()

3. 删除操作 (建议先看查询数据)

删除操作是SQL中的DELETE的封装,很简单,[QuerySet|obj].delete()

简单来讲,就是先查询,再删除

3.1 单个数据删除 obj.delete()

#### 删除id=25的书籍
Book.objects.filter(id=25).delete()

3.2 多条数据删除 QuerySet.delete()

#### 删除评论>3000的所有书籍
Book.objects.filter(comment_num__gt=3000).delete()

4. 查询数据

基本查询函数共计有三种

# filter: 返回所有符合条件的
# get: 只能返回1个,如果查出来多个,直接报错
# exclute: 返回除了查找的以外的所有的,相当于not

4.1 get查询函数

get方法只能返回一个,返回多个就会报错

Book.objects.get(id__exact=21)  # 返回一个Book对象
# xx_exact:严格模式 等同于 xx 
# 也就是说.get(id__exact=21) 和 .get(id=21) 是一样的

4.2 filter查询函数


filter返回满足条件的所有Book对象,返回QuerySet[Book_obj]

->  Book.objects.get(id__exact=21)
->  <Book: Book object (21)> # 返回的是一个Book对象

->	Book.objects.filter(id__exact=21) 
->  <QuerySet [<Book: Book object (21)>]> # 返回的是QuerySet

4.3 exclute 返回除了给出条件以外的所有值

例如:获取除了ID=2以外的所有Book对象

Book.objects.exclute(id=2) # 除了id=2的,全部都返回,返回QuerySet,其他参数与filter一样

4.4 获取数据个数

# 语法格式:
QuerySet.count()
obj.查询语句(条件).count()
Book.objects.exclude(id=22).count() # 返回id不为22的书籍的数量

5. 复杂单条件查询(不包含外键查询)

Django中所有的复杂条件查询都是以传入参数 字段名__函数的方法进行查询

5.1 值大小比较条件查询(日期/数字类型通用)

# 查询发布时间在2000年以后的所有图书
Book.objects.filter(pub_time__gt='2000-01-01')
# __gt : 大于某个值
# __gte: 大于等于某个值的所有值
# __lt : 小于某个值
# __lte: 小于等于某个值的所有值
# -> 如果返回不是一个,则会报错: Book.models.Book.MultipleObjectsReturned
# -> 所有日期相关的类型,都必须是 YYYY-MM-DD格式


Book.objects.filter(pub_time__year='2022') # 查询书籍发布时间在2022年的数据的所有书籍
# __year : 日期类型年=XX的,传字符串或者数字都可以
Book.objects.filter(pub_time__month='7') # 查询发布时间在7月的所有书籍
# __month : 月类型,同上

5.2 值含于(in)条件查询

# 查询作者名称是 "霍金" 或者 "雷欧幻象" 的所有书籍
# in条件不支持字符串查询,字符串有另外的方法
Book.objects.filter(author__in=["霍金", "雷欧幻象"])
# __in : 包含于[xx,xx]种的值,传QuerySet类型值

5.3 正则表达式条件查询

# 查询作者满足正则表达式 ^霍.* 的值 -> 霍开头
Book.objects.filter(author__regex=r'^霍.*')
# __regex : 满足正则表达式的值

5.4 字符串包含条件查询(LIKE)

# 查询作者名包含 "霍" 的所有书籍,类似于SQL中的 %霍%
Book.objects.filter(author__contains='霍')
# __contains : 包含"xx"字符串的值

5.5 字符串结尾/开头条件查询

# 查询作者以 "金"结尾的书籍
Book.objects.filter(author__endswith='金')
# __endswith : 以"xx"字符串结尾的值

# 查询作者以 "雷"开头的书籍
Book.objects.filter(author__startswith='雷')
# __startswith : 以"xx"字符串结尾的值

5.6 判断空值条件查询

# 返回所有作者不为空的书籍对象
Book.objects.filter(author__isnull=False)
# __isnull : 值是否为空的,传Bool类型

6. 复杂多条件 和/或 查询(Q对象)

6.1 多条件查询的几种方法

6.1.1 使用filter或者多参数

需求: 查询作者名包含霍金 并且 评论数 > 4000 的书籍

#### 多条件查询有多种方法
### 1. 多次使用filter
Book.objects.filter(author__contains='霍金').filter(comment_num__gt=4000)


### 2. 一个filter中传入多个参数
Book.objects.filter(author__contains='霍金', comment_num__gt=4000)

6.1.2 使用Q对象,实现 and 以及 or 查询

Q语法格式:

filter(Q(条件1) “|/&” Q(条件2) …更多条件)

# Q对象需要导入
from django.db.models import Q
# 格式:
# filter(Q(条件1) "|/&" Q(条件2) ...更多条件)
# Q对象的and以及or,需要使用 & | 运算符
# 查询作者名包含霍金 并且 评论数 > 4000 的书籍
Book.objects.filter(Q(author__contains='霍金') & Q(comment_num__gt=4000))

# 也许这个需求,看不出Q的方便性
# 现在需求改为,查询author中包含'霍金' 或者 评论数>4000的书籍
# 这时Q对象就可以实现

# 查询 作者名包含霍金 或者 评论数 > 4000 的书籍
Book.objects.filter(Q(author__contains='霍金') | Q(comment_num__gt=4000))

7. 不同字段之间的对比查询(F对象)

现在需求是,需要对比评论比销量高的数据,你该怎么办??

这里引入F对象

# F对象需要导入
from django.db.models import F
# 语法格式
# filter(条件=F(字段名称))
# 评论比购买数大的书籍
Book.objects.filter(comment_num__gt=F('sale'))
# 需求:
#    查询评论比销量大2倍的书籍或者销量大于10000的书籍
Book.objects.filter(Q(comment_num__gt=F('sale') * 2) | Q(sale__gt=100000))

8. 聚合查询函数

8.1 聚合函数的介绍和简单使用

众所周知,在SQL中,有对应的SUM(求和),AVG(均值)等函数,而Django也帮忙封装了相关的函数

函数的使用,需要在aggregate方法中传入函数

聚合函数,需要单独导入

from django.db.models import Sum, Avg # 导入求和,均值函数
# 语法格式
[model.objects|QuerySet].aggregate(函数1(字段),函数2(字段)...)
# -> dict 返回字典 {"字段_函数小写":结果,}

实现查询书籍的总销量和平均销量

Book.objects.aggregate(Sum('sale'),Avg('sale'))
-> {'sale__sum': 348123, 'sale__avg': 43515.375}

8.2 聚合函数与查询函数的连用

#### 需求:
####    查询数字作者名字中带 "霍金" 或者 书发布时间在2010年以后的 的书籍的平均销量以及平均评论
Book.objects.filter(Q(author__contains='霍金') | Q(pub_time__gt="2010-01-01")).aggregate(Avg('sale'),Avg('comment_num'))
# 使用Q对象,进行 "或" 查询,在返回的QuerySet中执行aggregate

9. 排序函数的使用 ORDER BY

排序函数就是Django封装的,SQL中的ORDER BY

# 语法格式:
# obj.order_by(字段名) 默认升序排序
# obj.order_by(-字段名) # 字段名前加减号代表降序排序


#### 需求:
####    返回升序排序评论数量数据 
####    返回降序排序销售数量数据

Book.objects.order_by('comment_num') # 直接order_by 升序排序
Book.objects.order_by('-comment_num') # "-字段名" 逆序排序

10. 表关联查询 JOIN 及关联筛选

SQL中的JOIN查询,可以让我们查询外键约束的相关数据,Django也进行了相关封装

先搞清楚我们两个数据库之间的关系

  1. Class Book (书籍信息表对象)

  2. Class Role (角色信息表对象)

其中Role的 “book” 字段,关联Book的 "id"字段

# 代码实现如下
book = models.ForeignKey('Book', on_delete=models.CASCADE, verbose_name='所属书籍') # 外键约束,约束于 'Book'类

10.1 用从表查主表 一对多关系

(“角色信息” 查 “书籍信息”) 一对多关系

10.1.1 从表查主表的值

# 从表查主表语法格式:
# "从表对象.get(条件).关联字段" -> 返回 主表对象


#### 需求:
####    现在要查询 角色"张飞"对应的书籍的销量

book_obj = Role.objects.get(name='张飞').book
-> 返回一个Book对象,可以调用其其他信息
book_obj.sale
-> 返回 "三国演义" 的销量
# 连起来
Role.objects.get(name='张飞').book.sale # 直接查询张飞对应书籍的销量

10.1.2 通过主表的值筛选从表的值 (不太好理解,多看看写的案例就懂了)

可能有些绕口,上面10.1.1的案例是通过"张飞"这个名字获得他对应的书籍的"销量"

现在需求变了,需要直接查询书籍销量大于1000的书籍里面的角色有哪些

# 语法格式:
# 从表对象.filter(从表与主表的关联字段__查询条件)
-> QuerySet

#### 需求:
#### 	查询书籍销量大于1000的书籍里面的角色
从表对象:Role.objects
关联字段:book
查询条件:sale__gt=1000
# 连起来就是
Role.objects.filter(book__sale__gt=1000)
-> QuerySet

10.2 主表查从表 多对一关系

(“书籍信息” 查 “角色信息”) 多对一关系

10.2.1 主表查从表的值

如果遇到这样的需求:查询三国演义这本书(主表)中所有的角色信息(从表)

# 语法格式:
# Django为主表封装了一个属性
# 属性命名格式: 从表(小写)_set
# 所以调用格式: 主表对象.从表(小写)_set -> QuerySet


#### 需求:
#### 	查询三国演义这本书(主表)中所有的角色信息(从表)
book = Book.objects.get(name='三国演义') # 先查询三国演义这本书
book.role_set.all()
-> QuerySet


#### 需求2:
#### 	查询三国演义这本书中 所有名字包含"飞"的角色:
Book.objects.get(name='三国演义').role_set.all().filter(name_contains='飞')
-> QuerySet

10.2 主表查从表 多对一关系

(“书籍信息” 查 “角色信息”) 多对一关系

10.2.1 主表查从表的值

如果遇到这样的需求:查询三国演义这本书(主表)中所有的角色信息(从表)

# 语法格式:
# Django为主表封装了一个属性
# 属性命名格式: 从表(小写)_set
# 所以调用格式: 主表对象.从表(小写)_set -> QuerySet


#### 需求:
#### 	查询三国演义这本书(主表)中所有的角色信息(从表)
book = Book.objects.get(name='三国演义') # 先查询三国演义这本书
book.role_set.all()
-> QuerySet


#### 需求2:
#### 	查询三国演义这本书中 所有名字包含"飞"的角色:
Book.objects.get(name='三国演义').role_set.all().filter(name_contains='飞')
-> QuerySet
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值