Django 避免每次for循环迭代都要访问数据库

Django 避免每次for循环迭代都要访问数据库,django,Django,我想将数据导出到Django中的Excel文件。首先,我得到所有成员: members_list = Member.objects\ .exclude(deleted=True) \ .annotate(num_calculations=Count('user__calculations'))\ .order_by("-user__date_joined") 然后我循环遍历成员并将其添加到excel文件: for row

我想将数据导出到Django中的Excel文件。首先,我得到所有成员:

members_list = Member.objects\
            .exclude(deleted=True) \
            .annotate(num_calculations=Count('user__calculations'))\
            .order_by("-user__date_joined")
然后我循环遍历成员并将其添加到excel文件:

for row in members_list:
            row_num += 1
            ws.write(row_num, 0, row.number or "", font_style)
            ws.write(row_num, 1, row.user.first_name or "", font_style)
            ws.write(row_num, 2, row.user.last_name or "", font_style)
            ws.write(row_num, 3, row.address or "", font_style)
            col_num = 3
            for calculation in calculations_per_month_last_12_months(row.number):
                col_num += 1
                ws.write(row_num, col_num, calculation['total_calculations'] or "", font_style)
最近12个月的每月计算功能如下所示:

items = list(Calculations.objects
                 .filter(user__member__number=member_number)
                 .filter(price_date__gte=datetime.datetime.now().today() - relativedelta(months=12))
                 .annotate(date=TruncMonth('price_date'))
                 .values('date')
                 .annotate(total=Count('id'))
                 .values('date', 'total')
                 .order_by('date'))

    result = []
    for month in range(12):
        date = timezone.now() - relativedelta(months=month)

        month_results = list(filter(lambda i: date <= i['date'] + relativedelta(months=1) < (date + relativedelta(months=1)), items))

        month_result = 0

        if month_results:
            month_result = month_results[0]['total']

        result.append({
            'total_calculations': month_result
        })

    return result
items=列表(计算.对象)
.filter(用户\成员\编号=成员\编号)
.filter(price_date_gte=datetime.datetime.now().today()-relativedelta(months=12))
.annotate(日期=TruncMonth('price_date'))
.值(“日期”)
.annotate(总计=计数('id'))
.值('日期','总计')
.按(‘日期’)订购
结果=[]
对于范围(12)内的月份:
日期=时区.now()-relativedelta(月=月)

month_results=list(filter)(lambda i:date您可以使用
prefetch_related
获取原始查询中的所有计算。它本质上执行SQL联接,以便将所有计算都变成一个查询。我还添加了
select_related('user')
,以避免对成员用户名进行额外查询

members_list = Member.objects\
        .exclude(deleted=True) \
        .annotate(num_calculations=Count('user__calculations'))\
        .order_by("-user__date_joined")\
        .select_related("user")\
        .prefetch_related("user__calculations")
然后在函数中,您可以传入
成员
对象,并且该对象已经预加载了计算,因此您可以跳过附加查询

def calculations_per_month_last_12_months(member):
    for month in range(12):
        date = timezone.now() - relativedelta(months=month)
        next_month = date + relativedelta(months=1)

        month_results = list(
            filter(
                lambda i: date <= i['date'] + relativedelta(months=1) < next_month,
                member.user.calculations
            )
        )

        month_result = 0

        if month_results:
            month_result = month_results[0]['total']

        yield {'total_calculations': month_result}
def每月计算数\u最近12个月(成员):
对于范围(12)内的月份:
日期=时区.now()-relativedelta(月=月)
下个月=日期+相对LTA(月=1)
月份结果=列表(
滤器(
lambda i:日期