我正在编写一个 Django View ,该 View 从数据库中查询对象列表以及相关字段中的一些信息。问题是数据库正在对 7 个对象执行 10 次查询。代码如下:
模板代码:
{% for resource in results %}
<li>
<a href="{{resource.url}}"> {{resource.url}}
{{resource.stats_set.values.0.avg}}</a>
<!-- truncated, the rest of the template just generates a form and
isn't causing any unnecessary sql -->
{% endfor %}
查看代码:
class ResourceList(generic.ListView):
model = Submissions
context_object_name = 'results'
template_name = 'url_list.html'
以及必要的模型:
class Submissions(models.Model):
LEVEL = (
('Introductory', 'Introductory'),
('Intermediate', 'Intermediate'),
('Academic', 'Academic'),
)
MEDIA_TYPE = (
('HTML', 'HTML'),
('PDF', 'PDF'),
('Video', 'Video'),
('Other', 'Other'),
)
id = models.AutoField(primary_key=True)
url = models.URLField(unique=True)
tags = models.ForeignKey(MajorTags, default=0)
level = models.CharField(choices=LEVEL, max_length=25)
media_type = models.CharField(choices=MEDIA_TYPE, max_length=25)
def __unicode__(self):
return self.url
def __str__(self):
return self.url
class Stats(models.Model):
url = models.ForeignKey(Submissions)
id = models.AutoField(primary_key=True)
avg = models.FloatField(default=0)
std_dev = models.FloatField(default=0)
def __unicode__(self):
return self.url.url + " " + str(self.avg)
def __str__(self):
return self.url.url + " " + str(self.avg)
问题的根源在于 {{resource.stats_set.values.0.avg}}
位。问题是,如果我尝试执行 queryset = Submissions.objects.all().select_lated('avg')
,我会收到一条错误消息,指出唯一的选项是 select_lated()
code> 是 tags
,这是有道理的,因为这是 Submissions
模型中唯一具有外键的字段。此时我的数据库结构已相当锁定,因此我无法更改数据库。我也无法查询统计信息
并从那里执行相反的操作,因为我需要获取尚无统计信息的数据。
如何减少正在运行的 SQL 查询数量?
最佳答案
您应该使用prefetch_related
它用于对反向外键或多对多关系进行有效查询:
来自文档:
prefetch_related()
Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.
def get_queryset(self,*args,**kwargs):
return Submissions.objects.all().prefetch_related('stats_set')
这将需要额外的查询,但其想法是它将立即获取所有相关信息,而不是每个 Submissions
对象获取一次。
顺便说一句,建议使用名词的单数作为模型类名称:Submission
而不是 Submissions
。
关于python - 如何优化此 Django View 的 SQL?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33831389/