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

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

native和static native区别

本文基于Hello JNI  如有疑惑,请看之前几篇文章。 native 与 static native java中 public native String helloJni();public native static String helloJniStatic();1212 JNI中 JNIEXPORT jstring JNICALL Java_com_test_g

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

bytes.split的用法和注意事项

当然,我很乐意详细介绍 bytes.Split 的用法和注意事项。这个函数是 Go 标准库中 bytes 包的一个重要组成部分,用于分割字节切片。 基本用法 bytes.Split 的函数签名如下: func Split(s, sep []byte) [][]byte s 是要分割的字节切片sep 是用作分隔符的字节切片返回值是一个二维字节切片,包含分割后的结果 基本使用示例: pa

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor

LabVIEW FIFO详解

在LabVIEW的FPGA开发中,FIFO(先入先出队列)是常用的数据传输机制。通过配置FIFO的属性,工程师可以在FPGA和主机之间,或不同FPGA VIs之间进行高效的数据传输。根据具体需求,FIFO有多种类型与实现方式,包括目标范围内FIFO(Target-Scoped)、DMA FIFO以及点对点流(Peer-to-Peer)。 FIFO类型 **目标范围FIFO(Target-Sc

019、JOptionPane类的常用静态方法详解

目录 JOptionPane类的常用静态方法详解 1. showInputDialog()方法 1.1基本用法 1.2带有默认值的输入框 1.3带有选项的输入对话框 1.4自定义图标的输入对话框 2. showConfirmDialog()方法 2.1基本用法 2.2自定义按钮和图标 2.3带有自定义组件的确认对话框 3. showMessageDialog()方法 3.1