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

 更新时间:2022年11月02日 10:36:06   作者:骑台风走  
在实际的开发中,模型之间经常存在复杂的关联关系,下面这篇文章主要给大家介绍了关于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. 使用

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 代码

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 代码

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 其他常用用法

# 获取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 常用的案例

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基础(29): select_related和prefetch_related的用法与区别

https://www.jb51.net/article/266493.htm

https://www.jb51.net/article/266498.htm

总结

到此这篇关于Django中select_related和prefetch_related用法与区别的文章就介绍到这了,更多相关select_related和prefetch_related用法与区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 手把手教你Python抓取数据并可视化

    手把手教你Python抓取数据并可视化

    很多小伙伴在提到python数据可视化的时候第一反应就是matplotlib库,但实际上python还有很多很好用的数据可视化的库,下面这篇文章主要给大家介绍了关于如何利用Python抓取数据并可视化的相关资料,需要的朋友可以参考下
    2022-05-05
  • 解决Djang2.0.1中的reverse导入失败的问题

    解决Djang2.0.1中的reverse导入失败的问题

    今天小编就为大家分享一篇解决Djang2.0.1中的reverse导入失败的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08
  • python中opencv Canny边缘检测

    python中opencv Canny边缘检测

    这篇文章主要介绍了python中opencv Canny边缘检测,Canny边缘检测是一种使用多级边缘检测算法检测边缘的方法。OpenCV提供了函数cv2.Canny()实现Canny边缘检测。更多相关内容需要的小伙伴可以参考下面文章内容
    2022-06-06
  • Python爬虫beautifulsoup4常用的解析方法总结

    Python爬虫beautifulsoup4常用的解析方法总结

    今天小编就为大家分享一篇关于Python爬虫beautifulsoup4常用的解析方法总结,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • Flask框架钩子函数功能与用法分析

    Flask框架钩子函数功能与用法分析

    这篇文章主要介绍了Flask框架钩子函数功能与用法,简单描述了flask框架钩子函数的概念、功能并结合实例形式分析了flask框架钩子函数的基本用法,需要的朋友可以参考下
    2019-08-08
  • 使用Python加密和解密PDF文件

    使用Python加密和解密PDF文件

    在日常工作和生活中,保护PDF文件的隐私和安全至关重要,Python提供了一些强大的库,使得加密和解密PDF文件变得相对简单,本文将详细介绍如何使用PyPDF2库来加密和解密PDF文件,需要的朋友可以参考下
    2025-03-03
  • pytorch模型的定义、修改、读取、断点续训深入解析

    pytorch模型的定义、修改、读取、断点续训深入解析

    模型定义是深度学习中重要的一环,PyTorch提供了强大而灵活的工具和函数,使我们能够轻松定义各种类型的深度学习模型,通过深入理解模型定义的原理和应用,我们能够更好地理解和设计自己的模型,从而提升深度学习任务的性能和效果
    2024-03-03
  • JupyterNotebook 如何调整输出窗口的显示效果

    JupyterNotebook 如何调整输出窗口的显示效果

    这篇文章主要介绍了JupyterNotebook 输出窗口的显示效果调整实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Python 数据化运营之KMeans聚类分析总结

    Python 数据化运营之KMeans聚类分析总结

    这篇文章主要介绍了Python 数据化运营KMeans聚类相关的一些总结,感兴趣的话一起来阅读下文吧
    2021-08-08
  • Pytorch中的Broadcasting问题

    Pytorch中的Broadcasting问题

    这篇文章主要介绍了Pytorch中的Broadcasting问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01

最新评论