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

Django中RawQuerySet无法用django-filter处理,如何转换为可用查询集?

问题:RawQuerySet无法被django-filter过滤(AttributeError: 'RawQuerySet' object has no attribute 'all')

报错信息

AttributeError at /tracker/
'RawQuerySet' object has no attribute 'all'

问题原因

使用django-filter处理原生SQL查询得到的RawQuerySet时,由于RawQuerySet不支持Django ORM的all()方法(而django-filter依赖该方法实现过滤逻辑),导致触发上述报错。

问题代码

def track1(request):
    sql = """
        select 1 as id,
            p.name project,
            i.title issue,
            u.name,
            replace(ROUND(t.time_spent/3600.0, 1)::text, '.', ',') as spent,
            TO_CHAR(t.spent_at + interval '2h', 'dd.mm.yyyy HH24:MI:SS') date_spent, substring(n.note for 300) note
        from issues i
        left join projects p on p.id = i.project_id
        left join timelogs t on t.issue_id = i.id
        left join users u on u.id = t.user_id
        left join notes n on n.id = t.note_id
        where (t.spent_at + interval '2h') between '2022-06-01' and '2022-06-30 23:59:59'
        order by 5, 1, 2
    """

    user_spent_on_project = UsersSpentOnProjects.objects.raw(sql)
    filter = UsersSpentOnProjectsFilter(request.GET, queryset=user_spent_on_project)
    user_spent_on_project = filter.qs

    context = {
        'user_spent_on_project' : user_spent_on_project,
        'filter' : filter
    }

    return render(request, 'trackApp/track1.html', context=context)

提问

有没有办法将这个RawQuerySet转换为类似Model.objects.all()的可被过滤的查询集?


解决方案

方法1:用Django ORM重写原生SQL(最优解)

将原生SQL逻辑转换为Django ORM查询,得到真正的QuerySet,直接兼容django-filter。示例代码如下(假设模型关联关系正确):

from django.db.models import F, Value, IntegerField, CharField
from django.db.models.functions import Round, Substr, Func
from django.utils import timezone
from datetime import datetime

def track1(request):
    # 转换时间条件:原SQL中t.spent_at + 2h在指定区间,等价于t.spent_at在[2022-05-31 22:00:00, 2022-06-30 21:59:59]
    start_date = timezone.make_aware(datetime(2022, 5, 31, 22, 0, 0))
    end_date = timezone.make_aware(datetime(2022, 6, 30, 21, 59, 59))

    # 用ORM构建查询
    queryset = Timelogs.objects.filter(
        spent_at__gte=start_date,
        spent_at__lte=end_date
    ).annotate(
        id=Value(1, output_field=IntegerField()),
        project=F('issue__project__name'),
        issue=F('issue__title'),
        name=F('user__name'),
        # 实现replace(ROUND(t.time_spent/3600.0,1)::text, '.', ',')
        spent=Func(
            Round(F('time_spent')/3600.0, 1),
            Value('.'), Value(','),
            function='replace',
            output_field=CharField()
        ),
        date_spent=Func(
            F('spent_at') + Value('2 hours'),
            Value('dd.mm.yyyy HH24:MI:SS'),
            function='TO_CHAR',
            output_field=CharField()
        ),
        note=Substr('note__note', 1, 300)
    ).select_related('issue__project', 'user', 'note').order_by('spent', 'id', 'project')

    # 直接使用django-filter
    filter = UsersSpentOnProjectsFilter(request.GET, queryset=queryset)

    context = {
        'user_spent_on_project': filter.qs,
        'filter': filter
    }

    return render(request, 'trackApp/track1.html', context=context)

方法2:将RawQuerySet转换为列表(仅适用于小数据量)

如果数据量不大,可以将RawQuerySet转换为列表,然后手动处理过滤逻辑:

user_spent_on_project = list(UsersSpentOnProjects.objects.raw(sql))

# 示例:根据request.GET中的project参数过滤
filtered_data = [item for item in user_spent_on_project if item.project == request.GET.get('project', '')]

这种方法会一次性加载所有数据到内存,无法利用数据库的过滤优化,仅适合小数据集场景。

方法3:自定义FilterSet适配RawQuerySet

如果必须保留原生SQL,可以重写django-filter的FilterSet,手动实现过滤逻辑:

import django_filters

class UsersSpentOnProjectsFilter(django_filters.FilterSet):
    project = django_filters.CharFilter(method='filter_project')

    class Meta:
        model = UsersSpentOnProjects
        fields = ['project']

    def filter_project(self, queryset, name, value):
        # 手动遍历RawQuerySet筛选符合条件的项
        return [item for item in queryset if item.project == value]

该方法同样需要遍历所有数据,性能较差,不推荐用于大数据量场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 10:33:17