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

如何在自定义Model QuerySet中使用Raw QuerySet?解决模型提前引用问题

解决Django自定义QuerySet提前引用模型及Raw QuerySet预取关联的问题

一、处理模型声明前引用自定义QuerySet的问题

你遇到的核心问题是Python的变量定义顺序限制:EntityModelQuerySet里提前用到了还未定义的Entity模型,直接写会触发未定义错误。这里有几个实用的解决思路:

方法1:动态获取模型(最推荐)

用Django的apps.get_model()在QuerySet方法里动态拉取模型,彻底避开提前引用的问题:

from django.apps import apps
from django.db import models

class EntityModelQuerySet(models.query.QuerySet):
    def search_by_item(self, id__list):
        # 替换成你的app名称和模型类名
        Entity = apps.get_model('your_app', 'Entity')
        qs = Entity.objects.raw('SELECT * FROM entity WHERE id IN %s', [id__list])
        return qs

# 后续正常定义模型
class Entity(models.Model):
    name = models.CharField(max_length=100)
    # 绑定自定义QuerySet
    objects = EntityModelQuerySet.as_manager()

方法2:先声明空模型再补全

如果觉得动态获取麻烦,可以先搭一个空模型架子,写完QuerySet后再补全字段:

from django.db import models

# 先声明空模型
class Entity(models.Model):
    class Meta:
        abstract = False  # 标记为非抽象模型

class EntityModelQuerySet(models.query.QuerySet):
    def search_by_item(self, id__list):
        qs = Entity.objects.raw('SELECT * FROM entity WHERE id IN %s', [id__list])
        return qs

# 补全模型字段和管理器
Entity.add_to_class('name', models.CharField(max_length=100))
Entity.objects = EntityModelQuerySet.as_manager()

方法3:直接写原生SQL字符串(适合简单场景)

如果你的raw查询不需要直接调用模型的objects方法,也可以直接写完整的SQL语句,不用提前引用模型:

class EntityModelQuerySet(models.query.QuerySet):
    def search_by_item(self, id__list):
        qs = self.raw('SELECT * FROM entity WHERE id IN %s', [id__list])
        return qs

二、处理Raw QuerySet结合prefetch_related的问题

划重点:Django的RawQuerySet本身不支持prefetch_related方法,因为它不属于标准QuerySet类型。要实现预取关联数据,需要手动模拟这个逻辑,步骤如下:

一对一/外键关联场景(比如Entity关联单个EntityItem)

# 1. 执行raw查询获取主模型实例
raw_entities = Entity.objects.raw('SELECT * FROM entity WHERE ...')

# 2. 提取所有关联的EntityItem ID
item_ids = [ent.item_id for ent in raw_entities if ent.item_id]

# 3. 批量查询需要的关联数据,只取需要的字段
prefetched_items = EntityItem.objects.filter(id__in=item_ids).only('name')
# 转成字典方便快速查找
item_map = {item.id: item for item in prefetched_items}

# 4. 手动把关联数据绑定到主模型实例
for ent in raw_entities:
    ent.item = item_map.get(ent.item_id)  # 无关联时返回None

一对多关联场景(比如一个Entity对应多个EntityItem)

# 1. 执行raw查询
raw_entities = Entity.objects.raw('SELECT * FROM entity WHERE ...')

# 2. 提取所有主模型ID
entity_ids = [ent.id for ent in raw_entities]

# 3. 批量查询关联数据并按主模型ID分组
prefetched_items = EntityItem.objects.filter(entity_id__in=entity_ids).only('name')
item_groups = {}
for item in prefetched_items:
    item_groups.setdefault(item.entity_id, []).append(item)

# 4. 手动绑定关联数据到主模型
for ent in raw_entities:
    ent.item_set = item_groups.get(ent.id, [])  # 无关联时返回空列表

这种手动预取的方式,既能实现prefetch_related减少查询次数的效果,又能严格控制返回的字段,和你原本的需求匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:33:12