Django--M部分整理总结二

本文深入讲解Django ORM操作,涵盖数据库配置、表创建、单表与多表操作、外键和多对多关系处理,以及聚合、分组、F和Q查询等高级功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先附上第一部分有关数据库配置,创建表和单表操作的内容地址:
https://blog.csdn.net/csdniter/article/details/93722416

关键摘要:

1.models.py里的类就代表数据库里的表

2.一个类的对象就代表表中的一行记录,当然一个类对象的集合就代表几行记录

3.K=models.ForeignKey(“类名”)字段会被自动把字段名加_id真实存在当前表里(K_id),不加_id的字段名(K)代表关联表中的一行数据(默认被关联表会添加一个隐藏字段:“小写关联表名_set”。也可通过K=models.ForeignKey(“类名”,related_name=“字段名”)进行自定义,这个字段可用于反向查询,不常用,后面有介绍。

4.K=models.ManyToManyField(“类名”)字段在当前表中不会创建对应字段,而是自动生成第三张表,但不能通过ORM直接操作,需要依赖关联表间接操作。字段名代表关联表对象集合(默认被关联表会添加一个隐藏字段:“小写关联表名_set”。也可通过K=models.ManyToManyField(“类名”,related_name=“字段名”)进行自定义

下面补充上多表操作

首先说一下表与表关系(两张表之间):
1.一对一:不常用,通常合并到一张表中
解决办法:加外键和unique属性
2,一对多或叫多对一 (重要!!,基础!!!)
解决办法:多的一方建外键到一方
另建外键的一方叫子表
被外键连接的一方叫父表
3.多对多
解决方法:建立一个中间表,建两个外键,加一个联合唯一
也就是转换为了一对多

准备工作(一对多)

下面是两个表,子表book(外键publish)绑定父表Publish(主键),Django会自动把子表带外键的字段名改为publish_id

class book(models.Model):
    name=models.CharField(max_length=20)
    price=models.IntegerField()
    pub_date=models.DateField()
    publish=models.ForeignKey("Publish",on_delete=models.CASCADE)
    # 谁多谁创外键,django默认绑定表名主键,会自动将有外键字段变成publish_id
    #on_delete=models.CASCADE是django2.x版本多的,1.x版本不用

class Publish(models.Model):
    name=models.CharField(max_length=32)
    city=models.CharField(max_length=32)

两个表是一对多的关系
一本书有一个对应出版社,一个出版社对应多本书

**1.----------------------增(create , save)-------------------

方式一:和单表一样
表名.objects.create(字段设置)
eg:

book.objects.create(name="python",price=12,pub_date="2018-2-2",publish_id=1) #增

要注意的是外键字段名,django会自动在后面加_id

方式二:
eg:

book.objects.create(name="python", price=12, pub_date="2018-2-2", publish=Publish.objects.filter(name="e")[0])

还是注意表名.objects.fliter(条件)拿到的是一个QuerySet集合!!!
所以这里加了一个索引【0】

-----------------查---------------

一,通过对象

1.从子表出发(找到一本书对于的唯一出版社)(正向查询)
先找到子表对象book_object=book.objects.get(name=“书籍名称”) 也就是一本书
然后对应到父表对象Publish_object=book_object.publish 就是一个出版社对象
通过Publish_object.字段就可拿到想要的信息
写在一起就是:book.objects.get(name=“书籍名称”).publish.字段

2.从父表出发(出版社出版过的书)(反向查询)
Publish_object=Publish.object.get(name=“出版社名称”)
book_object=Publish_object.book_set.all().value(“字段信息”)

这里book_set是定义到关联到book表的,因为可能不只有一个表关联
book_object是一个QuerySet集合,点values(“字段信息“)只是将信息以字典形式显示出来

这里比较难理解,总结一下:通过外键相连的两个字段查询拿到的都是记录信息,也就是对象

二,通过filter,values和双下划线__ (常用)

1.从子表出发(出版社出版过的书)(正向查询)
book.objects.fliter(publish__name=“出版社名称”).values(“字段”)

2.1.从父表出发(找到一本书对于的唯一出版社)
Publish.objects.fliter(book_set__name=“书名”).values(“name”) (反向查询)
book.objests.fliter(name=“书名”).values(“publish_name”) (正向查询)
和上面通过对象查找效果一样

详见上面的关键摘要

3.主表跨表查询(相当于sql里面的左外连接和右外连接)
book.objects.all().value(“name”,“publish__name”)
#拿到包含所有书的名字及对应出版社的名字 ,有书没有对应出版社的话显示None的一个QuerySet集合 当然一般书都有对应出版社

publish.objects.all().values(“name”,“book_set__name”)
#拿到包含所有出版社的名字及对应书的名字,有出版社没出书的话显示为None一个QuerySet集合

总结:从子表,外键出发就是正向查询,从父表,被关联表出发就是反向查询

在总结一点
ret=book,objects.all() #得到的ret是几个对象QuerySet集合: <QuerySet[bookobj,bookobj,bookobj,bookobj…]>
ret=book,objects.all().values(“name”,“price”)
得到的ret是一个字典QuerySet集合:
<QuerySet[{“name”:“python”,“price”:88}{“name”:“Liunx”,“price”:88}…]>
ret=book,objects.all().values_list(“name”,“price”)
得到的ret是一个元组QuerySet集合: <QuerySet[(“python”,88)(“linux”,88)…]>

准备工作(多对多)

下面是两个表:

class book(models.Model):
    name=models.CharField(max_length=20)
    price=models.IntegerField()
    pub_date=models.DateField()
    publish=models.ForeignKey("Publish",on_delete=models.CASCADE)
    author=models.ManyToManyField("Author")  #建立多对多的关系
class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField

分别是书籍和作者,
一本书可以有多个作者,一个作者可以出多本书,它们是多对多的关系

在加载之后,Django会创建三张表
除两张我们自己创建的表book和表author表
会自动创建第三张表book_author,不能在Django ORM里操作,因为django.models没有这个表对象。
但是在数据库里是真实存在的,可以正常使用。
还有一个就是在Django里的database里可以手动操作
通过自己创建的两张表的对象也能进行绑定修改
这里操作的都是第三张表,如果操作自己创建的两张表属于单表操作
eg:
1.添加关系信息(add): 一本书对应多个作者
book_object=book.object.get(“筛选条件”) #取到一个数据对象
author_object=Author.object.fliter(“字段筛选条件”) #取到一个作者对象集合
book_object.author.add( * author_object)

或者是book_object.author.add( 2) #把这本书和id=2的作者绑定起来
批量绑定 book_object.author.add([2,3,4]) #把这本书和id=2,3,4的作者分别绑定起来
注:这里不用jia星
一个作者对应多本书
Author.object.get(“筛选条件”).add(*(book.object.fliter(“字段筛选条件”)))

2.删除关系信息(remove,clear)
同上
添加一个:remove(数字):数字是第三个表中对应id,也就是作者id
book_object=book.object.get(“筛选条件”) #取到一个数据对象
book_object.author.clear() #把这本书的对应绑定作者信息全部删除

3.重置关系信息(set)
book_object=book.object.get(“筛选条件”) #取到一个书对象
book_object.author.set([2,3,5])
#把这本书的对应关系重置为2,3,5 #之前没有的添上,之前多出来的删掉

补充一个关系转换(不常用,可以不看)
两张表的多对多可以转换为三张表,两个一对多,加一个联合唯一
详见常用博客支援Django之Model操作里面的元信息及其他相关

.-----------------查---------------(多对多)

通过对象的方式和一对多相同,
book.objects.get(id=2).author.all().values(“name”)
(找到id=2这本书的所有作者名字)

二,通过filter,values和双下划线__ (,功能强大,常用)

(book.objects.filter(author__name=“yue”).values(“name”)
(找到作者名字为月写过的所有书的名字)

以上完

---------->聚合查询和分组查询

<1> 聚合查询aggregate(*args,**kwargs):

通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。

from django.db.models import Avg,Min,Sum,Max
Book.objects.all().aggregate(Avg('price'))   #{'price__avg': 34.35}
Book.objects.aggregate(average_price=Avg('price'))   #{'average_price': 34.35}
book.objects.fliter(author__name="yue").aggregate(Sum("price"))

aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它

**分组查询<2> annotate(*args,kwargs):

可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。

查询各个作者出的书的总价格:

from django.db.models import Avg,Min,Sum,Max
book.objects.values("author__name").annotate(Sum("price"))
book.objects.values("author__name").annotate(sumprice=Sum("price"))
#两条一样,就是第二条起了个名

---------->F查询和Q查询

**仅仅靠单一的关键字参数查询已经很难满足查询要求。
比如fliter(,)只能是条件的与关系
models.Tb1.objects.update(num=num+1)在sql中是正确的,在ORM中不行

此时Django为我们提供了F和Q查询:**

F 使用查询条件的值,专门取对象中某列值的操作

# from django.db.models import F
# models.Tb1.objects.update(num=F('num')+1)

Q 构建搜索条件

from django.db.models import Q

#1 Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询
q1=models.Book.objects.filter(Q(title__startswith='P')).all()
print(q1)#[<Book: Python>, <Book: Perl>]

# 2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。
Q(title__startswith='P') | Q(title__startswith='J')

# 3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合
Q(title__startswith='P') | ~Q(pub_date__year=2005)

注意:Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。

---------->惰性机制:

所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。执行之后会在QuerySet内置cache中创建

QuerySet特点:

<1> 可迭代的

<2> 可切片

queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
使用exists() QuerySet.exists() #有内容为Ture,无内容为False和iterator() QuerySet.iterator() #生成迭代器方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
会造成额外的数据库查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值