使用queryset.extra()按评论数和日期排序限制查询集(django)

1 投票
1 回答
1102 浏览
提问于 2025-04-15 23:20

我正在尝试根据每个对象的评论数量以及评论发布的时间范围来对一组对象进行排序和筛选。我使用的是 queryset.extra() 方法(这个方法是用在 django_comments 上,它利用了通用外键)。

我得到使用 queryset.extra() 这个想法(和代码)是从这里来的。这是我昨天提出的初始问题的后续问题(这说明我在进步)。

当前代码:

到目前为止,我的代码可以按评论数量进行排序;但是,我想扩展功能,能够传递一个时间范围参数(例如,7天),并返回在该时间范围内评论最多的帖子列表。

这是我视图的基本功能代码:

import datetime
from django.contrib.comments.models import Comment
from django.contrib.contenttypes.models import ContentType
from django.db.models import Count, Sum
from django.views.generic.list_detail import object_list

def custom_object_list(request, queryset, *args, **kwargs):
    '''Extending the list_detail.object_list to allow some sorting.

    Example: http://example.com/video?sort_by=comments&days=7

    Would get a list of the videos sorted by most comments in the 
    last seven days.
    '''

    try: # this is where I started working on the date business ... 
        days = int(request.GET.get('days', None))
        period = datetime.datetime.utcnow() - datetime.timedelta(days=int(days))
    except (ValueError, TypeError):
        days = None
        period = None

    sort_by = request.GET.get('sort_by', None)
    ctype = ContentType.objects.get_for_model(queryset.model)

    if sort_by == 'comments':
        queryset = queryset.extra(select={
            'count' : """
                SELECT COUNT(*) AS comment_count
                FROM django_comments
                WHERE
                    content_type_id=%s AND
                    object_pk=%s.%s
            """ % ( ctype.pk, queryset.model._meta.db_table, 
                queryset.model._meta.pk.name ),
            },
            order_by=['-count']).order_by('-count', '-created')

    return object_list(request, queryset, *args, **kwargs)

我尝试过的:

我对SQL不太熟悉,但我确实尝试手动添加另一个 WHERE 条件,看看能否有所进展:

    SELECT COUNT(*) AS comment_count
    FROM django_comments
    WHERE
        content_type_id=%s AND
        object_pk=%s.%s AND
        submit_date='2010-05-01 12:00:00'    

但这样做只是在搞乱我的排序顺序。

有没有什么想法可以让我添加这个额外的功能层?

感谢任何帮助或见解。

1 个回答

1

试试这个 [更新了以包含时间差(cutoff_date)]

 queryset = queryset.extra(select={
            'comment_count' : """
                SELECT COUNT(*)
                FROM django_comments
                WHERE
                    django_comments.content_type_id=%s AND
                    django_comments.object_pk=%s.%s AND
                    django_comments.submit_date < '%s'
            """ % ( ctype.pk, 
                    queryset.model._meta.db_table, 
                    queryset.model._meta.pk.name,
                    cutoff_date ),
            }).order_by('-comment_count', '-created')

为了得到一个合适的截止日期,我建议使用非常好用的 relativedelta,它来自于 python-dateutil 模块:

from datetime import relativedelta
from datetime import date

cutoff_date = date.today() - relativedelta(weeks =1) #relativedelta does all the heavy lifting

撰写回答