英文:
The difference between prefetch_related and model_set in Djnago
问题 {#heading}
我想知道在我需要检索外键模型对象时,最佳的流程是什么。
<br/>在views.py中使用**prefetch_related**是否是一个选择:
```python
queryset = queryset.prefetch_related('book_set')
context={objects:queryset}
或者直接在模板中使用model_set:
{% for attach in objects.book_set.all %}
哪个更好,哪一个对性能更好?
<details>
<summary>英文:</summary>
I wonder what is the best flow when I need to retrieve foreign key model objects.
=================================================================================
`<br/>is it to use `prefetch_related` in views.py like:
`
queryset = queryset.prefetch_related('book_set')
context={objects:queryset}
or to use directly in the template by **model_set**:
{% for attach in objects.book_set.all %}
what is better and which one is good for performance?
\</details\>
答案1
===
得分: 1
在Django中,https://docs.djangoproject.com/en/4.2/ref/models/querysets#prefetch-related用于提前选择所有父对象的所有相关对象,主要与`ManyToMany`字段和反向关系一起使用。
而https://docs.djangoproject.com/en/4.0/topics/db/queries#related-objects用于获取单个父对象的所有相关对象,这将明显增加数据库的访问次数。
因此,最好使用`prefetch_related`,因为它将显著减少数据库的访问次数。
如果您不进行反向关系并且具有外键关系,那么首选使用https://docs.djangoproject.com/en/4.2/ref/models/querysets#select-related。
就在模板或视图中编写查询而言,我建议始终在视图中执行所有查询,因为模板会增加额外的开销。
\<details\>
\<summary\>英文:\</summary\>
In Django https://docs.djangoproject.com/en/4.2/ref/models/querysets#prefetch-related is used to select all related objects for all parent objects in advance mostly used with `ManyToMany` field and a reverse relationship.
While as https://docs.djangoproject.com/en/4.0/topics/db/queries#related-objects is used to get all related objects of a single parent object which will definitely have more database hits.
Hence it is better to do `prefetch_related` as it will reduced the database hits significantly.
If you are not doing reverse relationship and have foreign key relation then https://docs.djangoproject.com/en/4.2/ref/models/querysets#select-related is prefered.
As far as writting queries in template or views is better. I would suggest always do all queries in the view as templates add extra level of overhead.
\</details\>
答案2
===
得分: 0
最佳方法取决于您的具体用例以及数据库的内容和大小。但一般来说,在`views.py`中使用`prefetch_related`可以通过减少数据库查询来提供更好的性能。
以下是一个示例,用于澄清这两种方法:
1. 在views.py中使用`prefetch_related()`:
```python
# views.py
queryset = Book.objects.all().prefetch_related('author')
context = {'books': queryset}
</code></pre>
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;"><code><span style="display:flex;"><span><span style="color:#75715e"><!-- template.html --></span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{% for book in books %}
</span></span><span style="display:flex;"><span> {{ book.title }} by {{ book.author.name }}
</span></span><span style="display:flex;"><span>{% endfor %}
</span></span></code></pre>
<p>在这种方法中,<code>prefetch_related('author')</code>会在单个查询中获取所有相关的作者,从而减少了数据库查询次数。</p>
<ol start="2">
<li>在模板中使用<code>model_set</code>:</li>
</ol>
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;"><code><span style="display:flex;"><span><span style="color:#75715e"><!-- template.html --></span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{% for book in books %}
</span></span><span style="display:flex;"><span> {{ book.title }} by
</span></span><span style="display:flex;"><span> {% for author in book.author_set.all %}
</span></span><span style="display:flex;"><span> {{ author.name }}
</span></span><span style="display:flex;"><span> {% endfor %}
</span></span><span style="display:flex;"><span>{% endfor %}
</span></span></code></pre>
<p>而在第二种方法中,每次迭代<code>book.author_set.all</code>都会访问数据库以检索相关的作者对象。这可能会导致多次数据库查询,并且可能会出现各种问题,特别是如果您有大量的书籍。</p>
<details>
<summary>英文:</summary>
<p>The best approach depends on your specific use case and the content and size of your database. However, generally using <code>prefetch_related</code> in the <code>views.py</code> can provide better performance by reducing database queries.</p>
<p>Here's an example to clarify both approaches:</p>
<ol>
<li>Using <code>prefetch_related()</code> in views.py:</li>
</ol>
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;"><code><span style="display:flex;"><span><span style="color:#75715e"># views.py</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>queryset <span style="color:#f92672">=</span> Book<span style="color:#f92672">.</span>objects<span style="color:#f92672">.</span>all()<span style="color:#f92672">.</span>prefetch_related(<span style="color:#f92672">&</span><span style="color:#75715e">#39;author&#39;)</span>
</span></span><span style="display:flex;"><span>context <span style="color:#f92672">=</span> {<span style="color:#f92672">&</span><span style="color:#75715e">#39;books&#39;: queryset}</span>
</span></span></code></pre>
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;"><code><span style="display:flex;"><span>&lt;!-- template.html --&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{% for book in books %}
</span></span><span style="display:flex;"><span> {{ book.title }} by {{ book.author.name }}
</span></span><span style="display:flex;"><span>{% endfor %}
</span></span></code></pre>
<p>In this approach, the <code>prefetch_related(&#39;author&#39;)</code> fetches all related authors in a single query, reducing the number of database hits.</p>
<ol start="2">
<li>Using <code>model_set</code> in the template:</li>
</ol>
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;"><code><span style="display:flex;"><span>&lt;!-- template.html --&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{% for book in books %}
</span></span><span style="display:flex;"><span> {{ book.title }} by
</span></span><span style="display:flex;"><span> {% for author in book.author_set.all %}
</span></span><span style="display:flex;"><span> {{ author.name }}
</span></span><span style="display:flex;"><span> {% endfor %}
</span></span><span style="display:flex;"><span>{% endfor %}
</span></span></code></pre>
<p>While on the second approach, each iteration of <code>book.author_set.all</code> hits the database to retrieve the related author object. This can result in multiple database queries, and different sort of problems, especially if you have a large number of books.</p>
</details>
<p></p>
</div>
```