Django中select_related和prefetch_related的用法与区别详解

2023-11-21 08:59

本文主要是介绍Django中select_related和prefetch_related的用法与区别详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

0. 本文借助django-debug-toolbar来展现效果

django-debug-toolbar的安装

1. 介绍

select_related:

将会根据外键关系(注意: 仅限单对单和单对多关系),在执行查询语句的时候通过创建一条包含SQL inner join操作的SELECT语句来一次性获得主对象及相关对象的信息

prefetch_related

对于多对多字段,你不能使用select_related方法,这样做是为了避免对多对多字段执行JOIN操作从而造成最后的表非常大。

Django提供了prefect_related方法来解决这个问题。

prefect_related可用于多对多关系字段,也可用于反向外键关系(related_name)。

相同点:

都作用于queryset对象上面

注意点:

  • 对与单对单或单对多外键ForeignKey字段,使用select_related方法
  • 对于多对多字段和反向外键关系,使用prefetch_related方法
  • 两种方法均支持双下划线指定需要查询的关联对象的字段名
  • 使用Prefetch方法可以给prefetch_related方法额外添加额外条件和属性。

2. 使用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

from django.db import models

  

class UserInfo(models.Model):

    username = models.CharField(verbose_name='用户名', max_length=225)

  

    def __str__(self):

        return self.username

  

class Tag(models.Model):

    name = models.CharField(verbose_name='标签名称', max_length=225)

  

    def __str__(self):

        return self.name

  

class Article(models.Model):

    title = models.CharField(verbose_name='标题', max_length=225)

    content = models.CharField(verbose_name='内容', max_length=225)

    # 外键

    username = models.ForeignKey(verbose_name='用户', to='UserInfo', on_delete=models.DO_NOTHING)

    tag = models.ManyToManyField(verbose_name='标签', to='Tag')

  

    def __str__(self):

        return self.title

2.1 原生的查询

2.1.1 代码

1

2

3

4

5

def article_list(request):

    if request.method == 'GET':

        # select_related---->queryset

        article_queryset = models.Article.objects.all()

        return render(request, 't2.html', context={'article_queryset': article_queryset})

2.1.2 图示

2.1.3 查询解释 

1.从图示我们可以看出来,一共进行13次查询,且有10次重复的!!!

原因是:当我们第一次查询时,返回的值,只有文章对象,对于标签以及用户,并没有查询,当前端界面需要这两个时,每循环一次,就会去数据库查询一次

2.为了避免重复查询,django提供select_related和prefetch_related方法来提升数据库查询效率,类似于SQL的JOIN方法。

3.效果就是当第一次查询时,进行连表,一次性把所有数据全部查询到

2.2 使用select_related

2.2.2 代码

1

2

3

4

5

6

7

8

9

10

from django.shortcuts import render

  

from blog import models

  

  

def article_list(request):

    if request.method == 'GET':

        # select_related---->queryset

        article_queryset = models.Article.objects.all().select_related('tag', 'username')

        return render(request, 't2.html', context={'article_queryset': article_queryset})

2.2.3 图示

 2.2.4 解释

可以看到现在只有三次查询,耗时大大减少

 2.2.5 其他常用用法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

# 获取id=1的文章对象同时,获取其相关username信息

Article.objects.select_related('username').get(id=1)

  

# 获取id=1的文章对象同时,获取其相关作者名字信息

Article.objects.select_related('username__username').get(id=1)

  

# 获取id=1的文章对象同时,获取其相关tag和相关作者名字信息。下面方法等同。

# 方式一:

Article.objects.select_related('tag', 'username__username').get(id=1)

# 方式二:

Article.objects.select_related('tag').select_related('username__username').get(id=1)

  

# 使用select_related()可返回所有相关主键信息。all()非必需。

Article.objects.all().select_related()

  

# 获取Article信息同时获取username信息。filter方法和selected_related方法顺序不重要。

# 方式一:

Article.objects.filter(tag__gt=3).select_related('username')

# 方式二:

Article.objects.select_related('username').filter(tag__gt=3)

2.3. 使用prefetch_related方法

对于多对多字段,你不能使用select_related方法,这样做是为了避免对多对多字段执行JOIN操作从而造成最后的表非常大。

2.3.1 常用的案例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

articles = Article.objects.all().select_related('category').prefecth_related('tags')

  

# 文章列表及每篇文章的tags对象名字信息

Article.objects.all().prefetch_related('tags__name')

  

# 获取id=13的文章对象同时,获取其相关tags信息

Article.objects.prefetch_related('tags').get(id=13)

  

# 获取文章列表及每篇文章相关的名字以P开头的tags对象信息

Article.objects.all().prefetch_related(

    Prefetch('tags', queryset=Tag.objects.filter(name__startswith="P"))

)

  

# 文章列表及每篇文章的名字以P开头的tags对象信息, 放在article_p_tag列表

Article.objects.all().prefetch_related(

    Prefetch('tags', queryset=Tag.objects.filter(name__startswith="P")),

to_attr='article_p_tag'

这篇关于Django中select_related和prefetch_related的用法与区别详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/401300

相关文章

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

Python常用命令提示符使用方法详解

《Python常用命令提示符使用方法详解》在学习python的过程中,我们需要用到命令提示符(CMD)进行环境的配置,:本文主要介绍Python常用命令提示符使用方法的相关资料,文中通过代码介绍的... 目录一、python环境基础命令【Windows】1、检查Python是否安装2、 查看Python的安

HTML5 搜索框Search Box详解

《HTML5搜索框SearchBox详解》HTML5的搜索框是一个强大的工具,能够有效提升用户体验,通过结合自动补全功能和适当的样式,可以创建出既美观又实用的搜索界面,这篇文章给大家介绍HTML5... html5 搜索框(Search Box)详解搜索框是一个用于输入查询内容的控件,通常用于网站或应用程

Before和BeforeClass的区别及说明

《Before和BeforeClass的区别及说明》:本文主要介绍Before和BeforeClass的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Before和BeforeClass的区别一个简单的例子当运行这个测试类时总结Before和Befor

mapstruct中的@Mapper注解的基本用法

《mapstruct中的@Mapper注解的基本用法》在MapStruct中,@Mapper注解是核心注解之一,用于标记一个接口或抽象类为MapStruct的映射器(Mapper),本文给大家介绍ma... 目录1. 基本用法2. 常用属性3. 高级用法4. 注意事项5. 总结6. 编译异常处理在MapSt

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

LiteFlow轻量级工作流引擎使用示例详解

《LiteFlow轻量级工作流引擎使用示例详解》:本文主要介绍LiteFlow是一个灵活、简洁且轻量的工作流引擎,适合用于中小型项目和微服务架构中的流程编排,本文给大家介绍LiteFlow轻量级工... 目录1. LiteFlow 主要特点2. 工作流定义方式3. LiteFlow 流程示例4. LiteF