gpt4 book ai didi

Python:访问数据库时摆脱嵌套 for 循环(模型? View ?)

转载 作者:行者123 更新时间:2023-12-01 01:06:38 25 4
gpt4 key购买 nike

我正在尝试解决基于 Django 的网站的性能问题,但对 Django 和 Python 语法知之甚少。我似乎已经正确地识别了问题。我似乎也知道下一步该做什么,但我无法掌握 Python/Django 语法来使一切正常工作。

class Company(models.Model):
name = models.CharField(max_length=100)
bic = models.CharField(max_length=100, blank=True)

def get_order_count(self):
return self.orders.count()

def get_order_sum(self):
total_sum = 0
for contact in self.contacts.all():
for order in contact.orders.all():
total_sum += order.total
return total_sum

class Contact(models.Model):
company = models.ForeignKey(
Company, related_name="contacts", on_delete=models.DO_NOTHING)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100, blank=True)

def get_order_count(self):
return self.orders.count()

class Order(models.Model):
order_number = models.CharField(max_length=100)
company = models.ForeignKey(Company, related_name="orders", on_delete=models.DO_NOTHING)
contact = models.ForeignKey(Contact, related_name="orders", on_delete=models.DO_NOTHING)
total = models.DecimalField(max_digits=18, decimal_places=9)
order_date = models.DateTimeField(null=True, blank=True)

def __str__(self):
return "%s" % self.order_number

我的预感是性能问题是由 get_order_sum 中的嵌套循环引起的。我的解决方案非常明确:嵌套的“fors”应该替换为一个简单的命令,该命令使用聚合并利用数据库自​​高度效的内部 SQL 功能。所以在我看来,解决方案应该是这样的:

return self.contacts.all().orders.all().aggregate(Sum('total'))

问题是我不知道如何正确编写我想要 Django/Python 执行的操作。请帮助我!

或者我错了,问题(或部分问题)出在我的 View 代码中吗?

<table>
<tr>
<th>Name</th>
<th>Order Count</th>
<th>Order Sum</th>
<th>Select</th>
</tr>
{% for company in company_list|slice:":100" %}
<tr>
<td>{{ company.name }}</td>
<td>{{ company.orders.count }}</td>
<td>{{ company.get_order_sum|floatformat:2 }}</td>
<td><input type="checkbox" name="select{{company.pk}}" id=""></td>
</tr>
{% for contact in company.contacts.all %}
<tr>
<td>- {{ contact.first_name }} {{ contact.last_name }}</td>
<td>Orders: {{ contact.orders.count }}</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
{% endfor %}
{% endfor %}
</table>

我也希望了解有关如何进一步改进此代码的任何其他提示和意见(尤其是从性能 POV 角度)。

最佳答案

关键是不要有过多的数据库查询(这与尽可能少的查询不同),并且正如您提到的,让数据库做它擅长的工作。

实际上,a) 您需要的所有数据在到达您的模板时都应该位于 company_list 中,这样您就不会从模板的循环内发送数据库查询, b) company_list 应以有效的方式填充数据。

from django.db.models import Prefetch, Sum, Count

contacts_with_orders = Prefetch(
'contacts',
queryset=Contact.objects.annotate(order_count=Count('orders'))
)

company_list = (Company.objects
.prefetch_related(contacts_with_orders)
.annotate(order_sum=Sum('orders__total'),
order_count=Count('orders'))
)

现在您可以执行循环并访问所有必需的数据,而无需任何进一步的查询:

for company in company_list:
company.name
company.order_sum
company.order_count
for contact in company.contacts.all():
contact.first_name
contact.order_count

虽然这应该比以前快几个数量级,但仍然相当繁重。还有更多的优化空间:如果需要,您可以通过仅查询所需的列而不是完整的行以及返回字典而不是对象来节省更多空间。请参阅only() , values() and values_list()to_attr Prefetch 中的参数。

关于Python:访问数据库时摆脱嵌套 for 循环(模型? View ?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55289893/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com