The usage and difference between select_related and prefetch_related

0. This article uses django-debug-toolbar to show the effect

(19 messages) Installation of django-debug- icon-default.png?t=M7J4toolbar

1 Introduction

select_related:

According to the foreign key relationship (note: only one-to-one and one-to-many relationships), the information of the main object and related objects will be obtained at one time by creating a SELECT statement containing the SQL inner join operation when executing the query statement.

prefetch_related

For many-to-many fields, you cannot use the select_related method, this is done to avoid performing JOIN operations on many-to-many fields and causing the final table to be very large.

Django provides the prefect_related method to solve this problem.

prefect_related can be used for many-to-many relationship fields and also for reverse foreign key relationships (related_name).

Same point:

Both act on the queryset object

be careful:

  • Use the select_related method for the ForeignKey field with a one-to-one or one-to-many foreign key

  • For many-to-many field and reverse foreign key relationships, use the prefetch_related method

  • Both methods support double underscores to specify the field name of the associated object to be queried

  • Use the Prefetch method to add additional conditions and attributes to the prefetch_related method.

2. Use

surface

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 Native query

2.1.1 Code

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 Illustration

2.1.3 Query Explanation 

1. We can see from the diagram that a total of 13 queries are made, and there are 10 repetitions! ! !

The reason is: when we query for the first time, the returned value is only the article object, and there is no query for tags and users. When the front-end interface needs these two, each cycle will go to the database to query

2. In order to avoid repeated queries, django provides select_related and prefetch_related methods to improve database query efficiency, similar to SQL's JOIN method.

3. The effect is that when the first query is made, the table is connected, and all the data is queried at one time.

2.2 Using select_related

2.2.2 Code

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 Diagram

 2.2.4 Interpretation

It can be seen that there are only three queries now, and the time-consuming is greatly reduced

 2.2.5 Other common usage

# 获取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. Using the prefetch_related method

For many-to-many fields, you cannot use the select_related method, this is done to avoid performing JOIN operations on many-to-many fields and causing the final table to be very large.

2.3.1 Common cases

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'
)

Reference in this article

Django basics (29): usage and difference between select_related and 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=1  https://cn.bing.com/ck/a? !&&p=f1ee206eac3dcc27JmltdHM9MTY2MjI0OTYwMCZpZ3VpZD0wZDM2NTliMy1hZDc5LTYwY2YtMDk4Mi00YmI2YWM1NzYxNmMmaW5zaWQ9NTE1Nw&ptn=7&hsh=3&fclid=0d3659b3-ad79-60cf-0982-4bb6ac57616c&u=a1aHR0cHM6Ly93d3cuY25ibG9ncy5jb20vd2FuZ3l1ZTA5MjUvcC8xMTExODczOS5odG1s&ntb=1

Guess you like

Origin blog.csdn.net/qq_52385631/article/details/126695685