简体   繁体   English

Django:使用values()和get_FOO_display()?

[英]Django: using values() and get_FOO_display()?

I'm trying to improve some existing code which originally took 3 minutes to prepare a large dataTable (then returned by Ajax). 我正在尝试改进一些现有的代码,这些代码最初耗时3分钟来准备一个大型dataTable(然后由Ajax返回)。 The old code iterated over a large querySet, gathering information from a variety of related objects. 旧代码遍历大型querySet,从各种相关对象收集信息。 From what I've read, and from monitoring the SQL log, iterating over querysets is generally a bad idea, because SQL is executed for each item. 从我所阅读的内容和监视SQL日志开始,迭代查询集通常是一个坏主意,因为SQL是针对每个项目执行的。 Instead, I've been using values to gather information in a single SQL statement, then iterating through that. 相反,我一直在使用值来在单个SQL语句中收集信息,然后迭代它。 Using this technique, I've reduced the execution time to under 15 seconds (and I'm still not done). 使用这种技术,我将执行时间减少到15秒以下(我还没有完成)。 However because I'm no longer using model objects, I can't use get_FOO_display() . 但是因为我不再使用模型对象,所以我不能使用get_FOO_display() Is there a way to use this functionality while using values()? 有没有办法在使用values()时使用此功能?

Simplified, the original was : 简化后,原来是:

for user in users:
   data.append(user.get_name_display())  # Appends 'Joe Smith'
return data

And the new code is: 新代码是:

for user in users.values('name'):
   data.append(user['name'])  # Appends 'JSmith001', which is incorrect
return data

Also, if there's some other way to preserve the creation of model objects yet only requires a single SQL statement on the backend, I'd love to know about it. 此外,如果有其他方法来保留模型对象的创建,但只需要在后端有一个SQL语句,我很想知道它。 Thanks! 谢谢!

In general, it'll probably be better and easier to use a Manager-based query that returns model objects. 通常,使用基于Manager的返回模型对象的查询可能会更好,更容易。 It sounds like the issue with your original approach is not that you were iterating over your queryset (as @ahmoo says, this isn't a performance issue), but that within your iteration loop you were getting additional related objects, requiring one or more additional queries for each record. 听起来你的原始方法的问题并不是你在迭代你的查询集(正如@ahmoo所说,这不是一个性能问题),但是在你的迭代循环中,你得到了额外的相关对象,需要一个或多个每条记录的附加查询。

There are several ways to improve performance with queries that still return model instances: 有几种方法可以使用仍返回模型实例的查询来提高性能:

  • It sounds like the most relevant is select_related() , which will effectively do a table join on the initial query to include data for all objects related by foreign keys. 听起来最相关的是select_related() ,它将有效地对初始查询执行表连接,以包括与外键相关的所有对象的数据。

  • If that's insufficient, you can also add data to your model instances with extra() , which allows you to stick subqueries into your SQL. 如果这还不够,您还可以使用extra()将数据添加到模型实例,这样您就可以将子查询粘贴到SQL中。

  • And if all that fails, you can perform raw SQL queries using the .raw() method on a Manager instance, which will still return model instances. 如果所有这些都失败了,您可以在Manager实例上使用.raw()方法执行原始SQL查询 ,该实例仍将返回模型实例。

Basically, if you can do it in SQL in a way that gives you one row per instance, there's a way to do it in Django and get model instances back. 基本上,如果您可以在SQL中以每个实例为一行的方式执行此操作,则可以在Django中执行此操作并获取模型实例。

To answer your original question, though, you can get the display name through the Field class - it's just ugly: 但是,要回答您的原始问题,您可以通过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')

iterating over querysets is generally a bad idea, because SQL is executed for each item 迭代查询集通常是一个坏主意,因为SQL是针对每个项执行的

That's not true. 这不是真的。 Below is taken from the official docs : 以下摘自官方文档

A QuerySet is iterable, and it executes its database query the first time you iterate over it QuerySet是可迭代的,并且在您第一次迭代它时执行其数据库查询

I think the problem has to do with the definition of the users from your code. 我认为问题与代码中users的定义有关。 What did you assign to it? 你分配给它的是什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM