第十二章 ORM的多表操作

Posted xu1296634150

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十二章 ORM的多表操作相关的知识,希望对你有一定的参考价值。

1.多对多操作

1.1 环境准备
# test.py
import os, django
os.environ.setdefault(DJANGO_SETTINGS_MODULE, 项目名.settings)
django.setup()
from app01 import models
# models.py
from django.db import models
# 出版社和书的一对多关系
class Publisher(models.Model):
    name = models.CharField(max_length=32)
    def __str__(self):
        return {}.format(self.name)
# 书籍信息 
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    pub = models.ForeignKey(Publisher, on_delete=models.CASCADE)
    def __str__(self):
        return {}.format(self.title)
# 作者信息
class Author(models.Model):
    name = models.CharField(max_length=32)
    books = models.ManyToManyField(Book, related_name=authors, related_query_name=xxx)
    def __str__(self):
        return {}.format(self.name)
1.2 基于对象的查询
  • 正向查询

author = models.Author.objects.get(pk=1)
# 关系管理对象,从1向多的方向拿都是关系管理对象
author.books
# 所有书籍
models.Author.objects.get(pk=1).books.all()
  • 反向查询(book表中没有外键字段)

  • 多对多也同样适用

# book对象
book = models.Book.objects.filter(title=python之旅).first()
# 关系管理对象,不指定related_name参数
book.author_set
# 获取所有作者
book.author_set.all()
# 指定related_name=‘authors‘
book.authors.all()
1.3 基于字段
# 不指定related_name/ related_query_name
author = models.Author.objects.filter(books__title=python之旅)
print(author)
# 不指定related_name/ related_query_name
book = models.Book.objects.filter(author__name=echo)
print(book)
# 指定related_name和related_query_name优先使用related_query_name=‘xxx‘
book = models.Book.objects.filter(xxx__name=echo)
print(book)
1.4 关系管理对象方法(6)
  • 通过关系管理对象获取多个关联值

# 关系管理对象
author = models.Author.objects.get(pk=1)
book = models.Book.objects.get(pk=1)
publisher = models.Publisher.objects.get(pk=1)

1.all()

books = author.books.all()
2. set([])
  • 重新设置数据

  • 值或对象

# 会覆盖历史数据
ret = author.books.set([书籍的id1,书籍的id2...])
# 返回值ret为None
# 可以写对象
author.books.set(modles.Book.objects.filter(pk__in[1,2,3]))
3. add()
  • 值或对象

# 添加数据,已有数据不会新增
author.books.add(书籍的id1,书籍的id2...)
# 添加对象,* 表示打散
author.books.add(*models.Book.objects.filter(pk__in=[书籍的id1,书籍的id2...]))
4. remove()
  • 值或对象

# 删除数据
author.books.remove(书籍的id1,书籍的id2...)
# 删除对象
author.books.remove(*models.Book.objects.filter(pk__in=[书籍的id1,书籍的id2...]))

5.clear()

# 清除author对象的所有的多对多关系
author.books.clear()

6.create(字段=值)

# 创建书的信息,并添加关联信息
obj = author.books.create(title=‘python, pub_id=1)
# 通过书创建作者
book = models.objects.get(pk=1)
obj = book.authors.create(name=diane)
1.5 外键的方法
  • 在外键中只能使用对象

  • pub和book关系

  • fitlter、get

1. all()
# 不指定related_name和related_query_name时,使用 类名_set获取关系管理对象
pub = models.Publisher.objects.get(pk=1)
pub.book_set.all()
2. set(QuerySet对象)
  • 对象列表

publisher = models.Publisher.objects.get(pk=1)
# 不能使用id ,只能使用对象
publisher.books.set(models.Book.bojects.fitler(pk__in[4,5]))
3. add(*QuerySet)
  • 一个个对象

publisher.books.add(*models.Book.bojects.fitler(pk__in[4,5]))
4. remove(*QuerySet)
  • 一个个对象

# remove/clear, 外键必须设置成 null=True参数
publisher.books.remove(*models.Book.bojects.fitler(pk__in[4,5]))

5.clear()

publisher.books.clear()

6.create(字段=值)

models.Publisher.objects.get(pk=1).books.create(title=xxx, price=10)
Note
  1. 对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

2. 聚合和分组

  1. aggregate()是QuerySet的一个终止子句,意思是说,它返回一个包含一些键值对的字典。

  2. 键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

  3. 用到的内置的聚合函数

from django.db.models import Avg, Sum, Max, Min, Count, F, Q
2.1 聚合
  • aggregate(聚合函数)

ret = models.Book.objects.all().aggregate(Max(price))
# 省略all()也会生效
ret = models.Book.objects.aggregate(Max(price))
# dict 类型,可以
print(ret)
# 如果给聚合结果重命名,注意位置和关键字传参的原则
ret = models.Book.objects.all().aggregate(Avg(price),max=Max(price))
# 返回值为字典,给终止子句
ret = models.Book.objects.filter(pk_gt=3).aggregate(Avg(price),max=Max(price))
2.2 分组
1. 基于字段
  • annotate注释,基于当前对象,添加一个注释字段

# .all()可以省略不写
ret = models.Book.objects[.all()].annotate(count=Count(author))
for i in ret:
    print(i.count)
2.分组方式1
# 以出版社的ID进行分组
ret = models.Publisher.objects.annotate(Min(book__price).values()
for i in ret:
    print(i)
3. 分组方式2
  • values表示分组的字段

ret = models.Book.objects.values(pub/pub_id/pub__name).annotate(Min(price))
for i in ret:
  print(i)
# 错误示范,如果values添加额外字段,则分组条件也会添加这个字段
ret = models.Book.objects.values(pub/pub_id/pub__name).annotate(Min(price)).values()
# 正确
ret = models.Book.objects.values(pub/pub_id/pub__name).annotate(min=Min(price)).values(pub_id, min)
  • 示例
# 统计每本书的作者个数
obj = models.Book.objects.values(title).annotate(Count(xxx__name))
for i in obj:
    print(i)
    
    
# 统计出每个出版社买的最便宜的书的价格
obj = models.Publisher.objects.values(name).annotate(Min(xxx__price))
for i in obj:
  print(i)

# 统计不止一个作者的图书,比较两种分组方式的区别
ret=models.Book.objects.annotate(count=Count(author__id)).filter(count__gt=1)
print(ret)
obj=models.Book.objects.values(title).annotate(count=Count(xxx__id)).filter(count__gt=1)
print(obj)

# 根据一本图书作者数量的多少对查询集 QuerySet进行排序
obj = models.Author.objects.annotate(count=Count(books__id)).order_by(count)
print(obj)

# 查询各个作者书的总价格
ret = models.Author.ojects.annotate(Sum(books__price)).values()
print(ret)

3. F和Q查询

3.1 F查询
  • F(‘字段名‘),取出字段值进行相应操作

ret = models.Book.objects.filter(price__gt=100)
print(ret)
1.比较两个字段值

# F,动态获取字段值
from django.db.models import F
ret = models.Book.objects.filter(sale__gt=F(‘inventory‘))

2.更新操作
# 更改一个对象,会更新所有的对象
obj = models.Book.objects.get(pk=1)
obj.sale = 100
obj.save()
  • 批量更新某一字段,update效率较高
# 批量更新,queryset对象支持update, 只更新sale字段
obj = models.Book.objects.filter(pk=1).update(sale=100)
# 直接更新到数据库
models.Book.objects.filter(pk=1).update(sale=F(sale)*2+10)
3.2 Q查询
  • 表示条件进行使用。

  • 使用逻辑关系(| 或, & 与,~ 非)

from django.db.models import Q
ret = models.Book.objects.filter(Q(pk__gt=3)|Q(pk__lt=2))
print(ret)
# q条件的组合,逻辑判断
models.Book.objects.filter(~Q(Q(pk__gt=3)|Q(pk__lt=2))&Q(price__gt=50))

4. 事务

  • 原子性、完整性

from django.db import transaction
try:
  with transaction.atomic():
    # orm操作为事务操作
      models.Publiser.objects.create(name=xxx)
      int(sss)
      models.Publiser.objects.create(name=xxx2)
except Exception as e:
   print(e)

5. Django终端打印SQL语句

  • Django项目的settings.py文件中,在最后复制粘贴如下代码

  • 即为Django项目配置上一个名为django.db.backends的logger实例即可查看翻译后的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,
        },
    }
}

6.执行原生sql

from django.db import connection
cursor=connection.cursor()
# 插入操作
cursor.execute("insert into hello_author(name) values(‘钱钟书‘)")
# 更新操作
cursor.execute("update hello_author set name=‘abc‘ where name=‘bcd‘")
# 删除操作
cursor.execute("delete from hello_author where name=‘abc‘")
# 查询操作
cursor.execute("select * from hello_author")
raw=cursor.fetchone()  # 返回结果
cursor.fetchall()      # 读取所有

 

以上是关于第十二章 ORM的多表操作的主要内容,如果未能解决你的问题,请参考以下文章

JAVA-初步认识-第十二章-JVM中的多线程分析

第十二章:使用C语言(Python语言)操作Sqlserver2019数据库

第十二章 并发编程

第十二章:Python の 网络编程进阶

进击的Python第十二章:mysql介绍与简单操作,sqlachemy介绍与简单应用

操作系统概念笔记——第十二章:大容量存储器结构的结构