如何在Django REST Framework API中遍历门店列表返回多门店销售指标
优化DRF API实现多门店指标查询
首先得说,你一开始想的循环遍历门店列表的思路虽然能跑,但效率真的不高——反复请求数据库会给VectorWise带来额外负载,门店多的时候尤其明显。更优的方案是直接优化SQL查询,一次拉取所有需要的数据,再处理成目标响应格式,同时还能兼容原来的单门店查询逻辑。
步骤1:动态构造安全的SQL查询
核心是根据是否传入store参数调整查询条件,而且绝对不能直接拼接SQL字符串(会有SQL注入风险!),要用参数化查询来传递变量:
from django.http import Response import pandas as pd # 假设你已经有数据库连接对象conn def sales_indicator_api(request): input_date = request.query_params.get('date') target_store = request.query_params.get('store') # 可选参数,不传则为None # 基础SQL模板,用占位符接收参数 sql_template = """ SELECT num_ett as store, sum(sales) as sales, sum(articles) as articles, sum(nb_clients) as nb_clients, sum(discount_rate) as discount_rate, sum(ind) as ind, sum(margin) as margin FROM dtm.fai_vte_web_ray_jou WHERE day = %(target_date)s {store_filter_clause} GROUP BY num_ett """ # 动态生成门店过滤条件 query_params = {'target_date': input_date} store_filter = "" if target_store: store_filter = "AND num_ett = %(target_store)s" query_params['target_store'] = target_store # 拼接最终SQL并执行参数化查询 final_sql = sql_template.format(store_filter_clause=store_filter) df = pd.read_sql(final_sql, conn, params=query_params)
步骤2:批量处理数据生成响应
接下来遍历查询结果的每一行,对每个门店执行你原来的指标计算逻辑,最后把所有门店的结果整理成列表返回:
# 用来存储所有门店的响应数据 response_data = [] for _, row in df.iterrows(): # 这里替换成你原来的指标计算逻辑,比如rank、progression_percentage等 # 示例用模拟值,你要换成实际的计算代码 rank = 3 progression_percentage = 7.5 nb_art_pass_caiss = row['articles'] nb_art_pass_caiss_prog = 4.2 basket = row['sales'] / row['nb_clients'] if row['nb_clients'] != 0 else 0 prog_basket = 2.8 remise = row['discount_rate'] marginN = row['margin'] marginN1 = marginN * 0.93 # 示例上年数据,替换成你的真实逻辑 # 构造单个门店的指标响应 store_item = { 'store': row['store'], 'Indicators': { 'dailyGrossTurnover': {'value': row['sales'], 'rank': rank, 'prog': progression_percentage}, 'dailyItems': {'itemCount': nb_art_pass_caiss, 'itemCountProg': nb_art_pass_caiss_prog}, 'dailyBasket': {'average': basket, 'averageProg': prog_basket}, 'dailyDiscount': remise, 'dailyMargin': {'currentYear': marginN, 'previousYear': marginN1} } } response_data.append(store_item) # 兼容原有逻辑:如果传了门店参数,返回单个对象;否则返回列表 if target_store: return Response(response_data[0]) else: return Response(response_data)
关键优化点说明
- 告别循环查库:一次SQL查询拉取所有目标数据,比循环遍历门店逐个请求高效太多,VectorWise作为列式数据库,批量查询的性能优势会更明显。
- 安全第一:用参数化查询替代字符串拼接,彻底避免SQL注入风险,这是生产环境必须遵守的规范。
- 兼容原有接口:保留了传入
store参数时返回单个门店数据的功能,不需要调用方修改现有逻辑。 - 逻辑复用:原来的指标计算逻辑可以直接复用在每一行数据上,不需要额外修改。
如果你的门店列表需要从数据库动态获取(比如不是固定范围),也可以先查一次所有门店编号,但依然推荐用批量查询的方式,而不是循环逐个请求。
内容的提问来源于stack exchange,提问作者S.Jackson
相关产品推荐
相关产品推荐

