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

Django执行原生SQL报Raw query must include the primary key错误求助

问题原因

Django的raw()方法有强制要求:当你通过模型类调用raw()执行原生SQL时,查询返回的结果集中必须包含该模型对应的主键字段,Django需要这个字段完成模型实例的映射。
你当前使用TransactionEntries.objects.raw(),对应home_transactionentries表(别名h_te),但你的SELECT语句里没有包含该表的主键h_te.id,因此触发报错。
另外你直接用f-string拼接用户ID到SQL语句里,存在SQL注入风险,不推荐该写法。


解决办法

方案1:调整SQL适配raw()方法

如果你需要将结果映射为TransactionEntries实例,可在SELECT中补充主键字段,同时改用Django raw() 方法自带的参数化传参能力规避注入风险:

def get(self, request):
    query = """
SELECT  h_te.id,
        u_c.name,
        sum(CASE
            WHEN h_te.to_pay_to_customer > h_te.pay_from_customer THEN
                h_te.to_pay_to_customer - h_te.pay_from_customer
            WHEN h_te.pay_from_customer > h_te.to_pay_to_customer THEN
                h_te.pay_from_customer - h_te.to_pay_to_customer
            ELSE 0
        end) as Total,
        u_c.owner_id
FROM home_transactionentries h_te
INNER JOIN home_transaction h_t
        ON h_te.transaction_id = h_t.id
INNER JOIN users_customer u_c
        ON u_c.id = h_t.customer_id
WHERE u_c.owner_id = %s
GROUP BY h_te.id, u_c.name, u_c.owner_id;
    """
    # 第二个参数传入查询参数,避免SQL注入
    query_set = TransactionEntries.objects.raw(query, [request.user.id])

注意GROUP BY子句中也要同步加上h_te.id,符合SQL聚合分组的语法规则。


方案2:直接用游标执行聚合查询(更推荐)

你的查询属于聚合统计场景,不需要映射为TransactionEntries模型实例,用数据库游标执行更高效,也不需要调整原有查询逻辑:

from django.db import connection

def get(self, request):
    query = """
SELECT  u_c.name,
        sum(CASE
            WHEN h_te.to_pay_to_customer > h_te.pay_from_customer THEN
                h_te.to_pay_to_customer - h_te.pay_from_customer
            WHEN h_te.pay_from_customer > h_te.to_pay_to_customer THEN
                h_te.pay_from_customer - h_te.to_pay_to_customer
            ELSE 0
        end) as Total,
        u_c.owner_id
FROM home_transactionentries h_te
INNER JOIN home_transaction h_t
        ON h_te.transaction_id = h_t.id
INNER JOIN users_customer u_c
        ON u_c.id = h_t.customer_id
WHERE u_c.owner_id = %s
GROUP BY u_c.name, u_c.owner_id;
    """
    with connection.cursor() as cursor:
        cursor.execute(query, [request.user.id])
        # 直接获取结果元组
        rows = cursor.fetchall()
        # 也可以转成字典格式方便接口返回
        columns = [col[0] for col in cursor.description]
        result = [dict(zip(columns, row)) for row in rows]

内容的提问来源于stack exchange,提问作者neeraj lamsal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:27:01