Python 如何提高我的';对于';在速度方面的环路性能?

Python 如何提高我的';对于';在速度方面的环路性能?,python,django,django-views,Python,Django,Django Views,我有一个for循环,迭代6907行几乎需要20秒。该循环完成了在给定查询集中生成唯一区域名称列表的任务。 我在代码中的不同位置放置了时间戳来记录计时。花费更多时间的“for”循环位于变量“t3”和“t4”之间 时间戳 t = 12:27:22:169533 t2 = 12:27:22:173535 t3 = 12:27:22:793567 6907 t4 = 12:27:42:907362 t5 = 12:27:43:242596 t6 = 12:27:43:242596 6907是我的que

我有一个for循环,迭代6907行几乎需要20秒。该循环完成了在给定查询集中生成唯一区域名称列表的任务。 我在代码中的不同位置放置了时间戳来记录计时。花费更多时间的“for”循环位于变量“t3”和“t4”之间

时间戳

t = 12:27:22:169533
t2 = 12:27:22:173535
t3 = 12:27:22:793567
6907
t4 = 12:27:42:907362
t5 = 12:27:43:242596
t6 = 12:27:43:242596
6907是我的queryset sales_数据的长度

views.py

class MSZoneProduct(generic.TemplateView):
    template_name = 'sales/MSZoneProduct.html'
    form_class = MSZoneProductForm

    def get(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            form = self.form_class(request.GET)
            context = {'form': form}
            if form.is_valid():
                zone_code_ = form.cleaned_data['zone_name']
                product_code_ = form.cleaned_data['product_name']

                t = datetime.now().strftime('%H:%M:%S:%f')
                print("t = " + t)
                product = Product.objects.get(product_code=product_code_)
                t2 = datetime.now().strftime('%H:%M:%S:%f')
                print("t2 = " + t2)
                sales_data = Sales.objects.filter(zone_code=zone_code_, product_code=product).select_related()
                t3 = datetime.now().strftime('%H:%M:%S:%f')
                print("t3 = " + t3)
                print(len(sales_data))
                regions = []
                message = ""
                regions_dict = {}
                for x in sales_data:
                    if x.region_name not in regions:
                        regions.append(x.region_name)
                    else:
                        continue
                t4 = datetime.now().strftime('%H:%M:%S:%f')
                print("t4 = " + t4)
                for x in regions:
                    sum_ = 0
                    for y in sales_data:
                        if y.region_name == x:
                            sum_ = sum_ + y.quantity
                    regions_dict[x] = sum_
                t5 = datetime.now().strftime('%H:%M:%S:%f')
                print("t5 = " + t5)
                if len(regions) == 0:
                    message = "There is no data available for this product in this particular region."

                context = {'form': form, 'message': message, 'data': regions_dict}
                t6 = datetime.now().strftime('%H:%M:%S:%f')
                print("t6 = " + t6)
                return render(request, 'sales/MSZoneProduct.html', context)

            return render(request, 'sales/MSZoneProduct.html', context)
        else:
            return redirect('/sales/')

使用列表理解构造的集合

regions = set(x.region_name for x in sales_data)
唯一的问题是你是否需要这些物品。它们可以在事件发生后进行排序,您可以根据它们是否成功添加到集合中,将它们附加到列表中


编辑:我同意在数据库中这样做是更好的方法(@Willem Van Onsem的答案),但这个答案将适用于任何不使用Django的人。

使用列表理解构建的集合

regions = set(x.region_name for x in sales_data)
唯一的问题是你是否需要这些物品。它们可以在事件发生后进行排序,您可以根据它们是否成功添加到集合中,将它们附加到列表中


编辑:我同意在数据库中这样做是更好的方法(@Willem Van Onsem的答案),但这个答案将与任何不使用Django的人相关。

改进for 可以在字典中以复杂度O(N)直接存储第一步的和


因此,销售额大于零的总地区将在字典中散列为键,其值为该地区的总销售额,可在固定时间访问。

改进for 可以在字典中以复杂度O(N)直接存储第一步的和


因此,销售额大于零的总地区将在字典中散列为键,其值为该地区的总销售额,可在固定时间访问。

通过dict理解和
itertools,可以更有效地完成从
sales_data=…
t5=…
的整个代码。groupby

from itertools import groupby
from operator import itemgetter
regions_dict = {k: sum(map(itemgetter('quantity'), g)) for k, g in groupby(Sales.objects.filter(zone_code=zone_code_, product_code=product).order_by('region_name').values('region_name', 'quantity'), itemgetter('region_name'))}

sales\u data=…
t5=…
的整个代码可以通过dict理解和
itertools更有效地完成。groupby

from itertools import groupby
from operator import itemgetter
regions_dict = {k: sum(map(itemgetter('quantity'), g)) for k, g in groupby(Sales.objects.filter(zone_code=zone_code_, product_code=product).order_by('region_name').values('region_name', 'quantity'), itemgetter('region_name'))}

根据您的视图,您希望汇总每个区域的数量。我们可以将所有这些逻辑移到数据库查询中。这不仅会使它更高效,而且更优雅:

from django.db.models import Sum

sales_data = Sales.objects.filter(
    zone_code=zone_code_, product_code=product
).values('region_name').annotate(
    total_quantity=Sum('quantity')
).order_by('region_name')
这将产生一个
查询集
,其中包含两个元素的字典:
映射到区域名称的“区域名称”
,以及汇总该区域数量的
总数量

接下来,我们可以将其转换为字典
regions\u dict

regions_dict = { r['region_name']: r['total_quantity'] for r in sales_data }

根据您的视图,您希望汇总每个区域的数量。我们可以将所有这些逻辑移到数据库查询中。这不仅会使它更高效,而且更优雅:

from django.db.models import Sum

sales_data = Sales.objects.filter(
    zone_code=zone_code_, product_code=product
).values('region_name').annotate(
    total_quantity=Sum('quantity')
).order_by('region_name')
这将产生一个
查询集
,其中包含两个元素的字典:
映射到区域名称的“区域名称”
,以及汇总该区域数量的
总数量

接下来,我们可以将其转换为字典
regions\u dict

regions_dict = { r['region_name']: r['total_quantity'] for r in sales_data }

您可能可以在db中执行其中一些操作。显示您的模型和预期输出。您可能可以在数据库中执行其中一些操作。显示您的模型和预期输出。样式非常紧凑。什么是复杂性?@atterson:linear,因为
groupby
在线性时间内工作,
sum(…)
在线性时间内对元素求和。@WillemVanOnsem和groupby不会增加复杂性,对吗?@atterson:itertools的groupby将组“突发”在一起。因此,它不会检查“队列”后面是否有属于同一组的其他项目。优点是它可以线性工作,而且可以处理无限多个列表。因此,如果你想使用真正的团队,你需要先下单。@WillemVanOnsem很高兴知道。在这种情况下,这个答案是一流的。它的风格是非常python和紧凑。什么是复杂性?@atterson:linear,因为
groupby
在线性时间内工作,
sum(…)
在线性时间内对元素求和。@WillemVanOnsem和groupby不会增加复杂性,对吗?@atterson:itertools的groupby将组“突发”在一起。因此,它不会检查“队列”后面是否有属于同一组的其他项目。优点是它可以线性工作,而且可以处理无限多个列表。因此,如果你想使用真正的团队,你需要先下单。@WillemVanOnsem很高兴知道。在这种情况下,这个答案很好。这是专家的想法。非常感谢@WillemVanOnsem。这个解决方案真的很快。这是专家的想法。非常感谢@WillemVanOnsem。这个解决方案真的很快。