0. 本文借助django-debug-toolbar来展现效果
(19条消息) django-debug-toolbar的安装_骑台风走的博客-CSDN博客https://blog.csdn.net/qq_52385631/article/details/126695534?spm=1001.2014.3001.5501
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 modelsclass UserInfo(models.Model): username = models.CharField(verbose_name='用户名', max_length=225) def __str__(self): return self.usernameclass Tag(models.Model): name = models.CharField(verbose_name='标签名称', max_length=225) def __str__(self): return self.nameclass 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 renderfrom blog import modelsdef 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的用法与区别 (qq.com)
https://cn.bing.com/ck/a?!&&p=e0abbfe758bda72aJmltdHM9MTY2MjI0OTYwMCZpZ3VpZD0wZDM2NTliMy1hZDc5LTYwY2YtMDk4Mi00YmI2YWM1NzYxNmMmaW5zaWQ9NTEzNA&ptn=7&hsh=3&fclid=0d3659b3-ad79-60cf-0982-4bb6ac57616c&u=a1aHR0cHM6Ly93d3cuY25ibG9ncy5jb20vY2NvcnovcC82MDk3MTcxLmh0bWw&ntb=1https://cn.bing.com/ck/a?!&&p=f1ee206eac3dcc27JmltdHM9MTY2MjI0OTYwMCZpZ3VpZD0wZDM2NTliMy1hZDc5LTYwY2YtMDk4Mi00YmI2YWM1NzYxNmMmaW5zaWQ9NTE1Nw&ptn=7&hsh=3&fclid=0d3659b3-ad79-60cf-0982-4bb6ac57616c&u=a1aHR0cHM6Ly93d3cuY25ibG9ncy5jb20vd2FuZ3l1ZTA5MjUvcC8xMTExODczOS5odG1s&ntb=1