我正在尝试改进一些现有的代码,这些代码最初耗时3分钟来准备一个大型dataTable(然后由Ajax返回)。旧代码遍历大型querySet,从各种相关对象收集信息。从我所阅读的内容和监视SQL日志开始,迭代查询集通常是一个坏主意,因为SQL是针对每个项目执行的。相反,我一直在使用值来在单个SQL语句中收集信息,然后迭代它。使用这种技术,我将执行时间减少到15秒以下(我还没有完成)。但是因为我不再使用模型对象,所以我无法使用get_FOO_display()。有没有办法在使用values()时使用此功能?
简化,原文是:
for user in users:
data.append(user.get_name_display()) # Appends 'Joe Smith'
return data
新代码是:
for user in users.values('name'):
data.append(user['name']) # Appends 'JSmith001', which is incorrect
return data
此外,如果还有其他方法可以保留模型对象的创建,但只需要在后端使用单个SQL语句,我很乐意了解它。谢谢!
答案 0 :(得分:6)
通常,使用返回模型对象的基于Manager的查询可能会更好,更容易。这听起来像你原来的做法的问题不在于你遍历你的查询集(如@ahmoo说,这不是一个性能问题),但你的迭代循环中你获得额外的相关对象,需要一个或多个每条记录的附加查询。
有几种方法可以提高仍然返回模型实例的查询的性能:
这听起来像最相关的是select_related()
,这将有效地执行初始查询表连接到包括用于由外键关联的所有对象的数据。
如果这还不够,您还可以使用extra()
将数据添加到模型实例,这样您就可以将子查询粘贴到SQL中。
如果一切都失败了,您可以在Manager实例上使用.raw()
方法执行raw SQL queries,该实例仍将返回模型实例。
基本上,如果您可以在SQL中以每个实例为一行的方式执行此操作,则可以在Django中执行此操作并返回模型实例。
要回答你的原始问题,你可以通过Field类获得显示名称 - 它只是丑陋:
def get_field_display(klass, field, value):
f = klass._meta.get_field(field)
return dict(f.flatchoices).get(value, value)
# usage
get_field_display(User, 'name', 'JSmith001')
答案 1 :(得分:3)
迭代查询集通常是一个坏主意,因为SQL是针对每个项执行的
那不是真的。以下内容摘自the official docs:
QuerySet是可迭代的,并且在您第一次迭代它时执行其数据库查询
我认为问题与代码中users
的定义有关。你分配给它的是什么?