Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从queryset建立最高价格列表的最有效方法?_Python_Mysql_Django_Django Queryset_Django Orm - Fatal编程技术网

Python 从queryset建立最高价格列表的最有效方法?

Python 从queryset建立最高价格列表的最有效方法?,python,mysql,django,django-queryset,django-orm,Python,Mysql,Django,Django Queryset,Django Orm,在我的应用程序的一个页面中,我试图显示每家公司最昂贵的汽车。我的模型大致如下: class Company(models.Model): id = models.IntegerField(primary_key=True) company = models.CharField(max_length=100) headcount = models.IntegerField(null=False) info = models.CharField(max_length=

在我的应用程序的一个页面中,我试图显示每家公司最昂贵的汽车。我的模型大致如下:

class Company(models.Model):
    id = models.IntegerField(primary_key=True)
    company = models.CharField(max_length=100)
    headcount = models.IntegerField(null=False)
    info = models.CharField(max_length=100)

class Car(models.Model):
    id = models.IntegerField(primary_key=True)
    company_unique = models.ForeignKey(Company)
    company = models.CharField(max_length=50)
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=9, decimal_places=2, default=0.00)
所以,我想建立一个由每家公司的单个最昂贵的汽车对象组成的列表

我是这样处理这个问题的:

company_list = Company.objects.all()
most_expensive = []
for company in company_list:
    most_expensive.append(Car.objects.filter(company_unique=company.id).order_by("-price")[0])
然而,这似乎是一种非常低效的方法。我可以通过Django调试工具栏看到,这段代码占用了太多的mysql查询


有人能提出一个更好的方法来创建这个列表,它可能只会对MySQL造成一次或两次影响吗?

我发誓这就是我能够处理它的方式,但似乎我一定是弄错了

我认为这是可能的:

以下是原始SQL,它有它的优点,但我觉得可能有更干净的方法:

from django.db import connection

cursor = connection.cursor()
cursor.execute("SELECT Max(price), company_unique FROM Car GROUP BY company_unique");
price_company = cursor.fetchall()

# This still does one query per car, only it fetches one item at a time.
most_expensive = [Cars.objects.get(price=pc[0],company_unique=pc[1]) 
                    for pc in price_company]
如果您确实想将其限制为一个查询,那么您可以利用
raw

most_expensive = Cars.objects.raw("""
   SELECT * FROM Cars 
     INNER JOIN 
       (SELECT Max(price) as price, company_unique FROM Car GROUP BY company_unique) m 
       ON m.price = Cars.price, m.company_unique = Cars.company_unique
""")
使用
raw
的问题在于它不是数据库不可知的,因此任何重构都需要重新编写此查询。(例如,Oracle具有不同的辅助查询语法)


我想我应该指出,
SELECT Max(price)as price,company_unique FROM Car GROUP BY company_unique
查询无论如何都会执行-如果您使用的是更Django的本机解决方案,它将发生在幕后。

虽然您处理的是一个非常常见的情况,似乎缺少一个显而易见的解决办法

解决方案1,可在中找到。您可能可以尝试以下方法:

companies = Company.objects.annotate(max_price=Max('car__price'))
values = tuple((company.id, company.max_price) for company in companies)

expensive_cars = Car.objects.extra(where=['(company_unique_id, price) IN %s' % (values,)])
不能说我喜欢这个解决方案-
。应该避免额外的
,但我想不出更好的方法。我也不完全确定这是否会奏效

解决方案2,次优。你可以利用

这肯定可以在两个查询中提取所有内容,但这是非常浪费的,因为它会将与给定的
公司集
相关的所有
汽车
加载到内存中。请注意,
list()
部分不是可选的:无论您在何处获取切片或索引,查询集都会被复制并生成一个单独的DB查询,因此会否定预取,而实例化列表时将使用所述预取的结果


如果您以后需要访问公司,如
Car.company
,请不要回避使用Erik在评论中建议的
select\u related

向公司添加一个名为“priciest\u Car”的字段,并覆盖保存,以便每次保存公司时,你循环浏览它的相关汽车,把最贵的设定为最贵的。然后,当你需要为每家公司呼叫最昂贵的汽车时,你可以在每家公司中循环,将
company.priciest_car
添加到列表中。这是一个循环,每个循环调用一个sql。唯一的额外工作是当你拯救一家公司时,但这将是每家公司的工作,所以不会花费太长时间。如果确实如此,请找到一种方法,仅当您知道已更改时,才将其设置为“priciest_car”字段。

使用这些内置项可能会减少您的查询计数:该查询集似乎不再包含汽车对象。至少,它不再具有像“name”这样的Car对象的所有字段。当我将其传递到模板中时,会生成一个具有正确行数的表,但每个单元格都是空的。这是一个不同的问题。您的模板中可能有错误(问题中没有包含该模板,因此此处不相关)。这确实回答了问题。我看不出这是如何以任何方式回答问题的。如果您阅读OP给出的示例,很明显,他希望获得
汽车
实例,而不仅仅是最高价格。我认为解决方案1是我要走的路。在我的例子中,我发现我必须将这两个值转换为字符串,例如:
values=tuple((str(company.id),str(company.max\u price))for company In companys)
。。。否则我会得到MySQL错误。
companies = Company.objects.annotate(max_price=Max('car__price'))
values = tuple((company.id, company.max_price) for company in companies)

expensive_cars = Car.objects.extra(where=['(company_unique_id, price) IN %s' % (values,)])
prefetch = Prefetch('cars', queryset=Car.objects.order_by('-price'), to_attr='cars_by_price')
companies = Company.objects.prefetch_related(prefetch)

most_expensive_cars = []
for company in companies:
    most_expensive_cars.append(list(company.cars_by_price.all())[0])