Select 相关执行查询
Select related executes queries
我无法使 select_related
使用以下配置:
型号:
class Text(models.Model):
author = models.ForeignKey('authors.Author',
on_delete=models.SET_NULL,
blank=True,
null=True)
作者模型:
class Author(models.Model):
name = models.CharField(max_length=200)
def get_absolute_url(self):
kwargs = {'pk': self.pk}
return reverse('author-detail', kwargs=kwargs)
查看
在视图中,我使用 select_related
函数来避免在查询文本作者时访问数据库,例如:mytext.author
:
class TextsViewTest(TestCase):
def text_view(request,
pk,
template_name='texts/detail.html'):
source_text = Text.objects.select_related('author').get(pk=pk)
return render(request, template_name,
{
'source': source_text,
})
测试
根据 select_related 它在访问 Text.author
关系时不应该访问数据库,但是在测试它时:
def test_layout_content_header__uses_prefetched_relationships(self):
author = Author.objects.create(name="foobar")
source_text = Text.objects.create(author=author)
context = {'source': source_text}
with self.assertNumQueries(0):
from django.template.loader import render_to_string
rendered = render_to_string("text/_content_header.html", context)
模板
text/content_header.html
:
{% if source.author %} by <em><a href="{{source.author.get_absolute_url}}">{{source.author.name}}</a></em>{% endif %}
输出
./manage test texts.test_views
显示命中:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_layout_content_header__uses_prefetched_relationships (author.tests.test_views.TextsViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/.../text/tests/test_views.py", line 1035, in test_layout_content_header__uses_prefetched_relationships
source_text.author
File "/.../lib/python3.6/site-packages/django/test/testcases.py", line 80, in __exit__
'%d. %s' % (i, query['sql']) for i, query in enumerate(self.captured_queries, start=1)
AssertionError: 1 != 0 : 1 queries executed, 0 expected
Captured queries were:
1. SELECT "authors_author"."id", "authors_author"."name", FROM "authors_author" WHERE "authors_author"."id" = 1
----------------------------------------------------------------------
Ran 1 test in 0.489s
FAILED (failures=1)
Destroying test database for alias 'default'...
有什么想法吗?
看起来您没有在测试中使用您的视图代码。尝试将相同的查询复制到您的测试中,例如:
context = {'source': Text.objects.select_related('author').get(pk=source_text.pk)}
with self.assertNumQueries(0):
from django.template.loader import render_to_string
rendered = render_to_string("text/_content_header.html", context)
或者重用视图代码(好像是在Test Case里声明的吧?)
with self.assertNumQueries(1):
self.text_view(MagicMock(), source_text.pk)
尽管您可能需要指定更高级的请求模拟,例如使用 RequestFactory
我无法使 select_related
使用以下配置:
型号:
class Text(models.Model):
author = models.ForeignKey('authors.Author',
on_delete=models.SET_NULL,
blank=True,
null=True)
作者模型:
class Author(models.Model):
name = models.CharField(max_length=200)
def get_absolute_url(self):
kwargs = {'pk': self.pk}
return reverse('author-detail', kwargs=kwargs)
查看
在视图中,我使用 select_related
函数来避免在查询文本作者时访问数据库,例如:mytext.author
:
class TextsViewTest(TestCase):
def text_view(request,
pk,
template_name='texts/detail.html'):
source_text = Text.objects.select_related('author').get(pk=pk)
return render(request, template_name,
{
'source': source_text,
})
测试
根据 select_related 它在访问 Text.author
关系时不应该访问数据库,但是在测试它时:
def test_layout_content_header__uses_prefetched_relationships(self):
author = Author.objects.create(name="foobar")
source_text = Text.objects.create(author=author)
context = {'source': source_text}
with self.assertNumQueries(0):
from django.template.loader import render_to_string
rendered = render_to_string("text/_content_header.html", context)
模板
text/content_header.html
:
{% if source.author %} by <em><a href="{{source.author.get_absolute_url}}">{{source.author.name}}</a></em>{% endif %}
输出
./manage test texts.test_views
显示命中:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_layout_content_header__uses_prefetched_relationships (author.tests.test_views.TextsViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/.../text/tests/test_views.py", line 1035, in test_layout_content_header__uses_prefetched_relationships
source_text.author
File "/.../lib/python3.6/site-packages/django/test/testcases.py", line 80, in __exit__
'%d. %s' % (i, query['sql']) for i, query in enumerate(self.captured_queries, start=1)
AssertionError: 1 != 0 : 1 queries executed, 0 expected
Captured queries were:
1. SELECT "authors_author"."id", "authors_author"."name", FROM "authors_author" WHERE "authors_author"."id" = 1
----------------------------------------------------------------------
Ran 1 test in 0.489s
FAILED (failures=1)
Destroying test database for alias 'default'...
有什么想法吗?
看起来您没有在测试中使用您的视图代码。尝试将相同的查询复制到您的测试中,例如:
context = {'source': Text.objects.select_related('author').get(pk=source_text.pk)}
with self.assertNumQueries(0):
from django.template.loader import render_to_string
rendered = render_to_string("text/_content_header.html", context)
或者重用视图代码(好像是在Test Case里声明的吧?)
with self.assertNumQueries(1):
self.text_view(MagicMock(), source_text.pk)
尽管您可能需要指定更高级的请求模拟,例如使用 RequestFactory