You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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)

关键优化点说明

  1. 告别循环查库:一次SQL查询拉取所有目标数据,比循环遍历门店逐个请求高效太多,VectorWise作为列式数据库,批量查询的性能优势会更明显。
  2. 安全第一:用参数化查询替代字符串拼接,彻底避免SQL注入风险,这是生产环境必须遵守的规范。
  3. 兼容原有接口:保留了传入store参数时返回单个门店数据的功能,不需要调用方修改现有逻辑。
  4. 逻辑复用:原来的指标计算逻辑可以直接复用在每一行数据上,不需要额外修改。

如果你的门店列表需要从数据库动态获取(比如不是固定范围),也可以先查一次所有门店编号,但依然推荐用批量查询的方式,而不是循环逐个请求。

内容的提问来源于stack exchange,提问作者S.Jackson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:49:27