Django 类似连接的 queryset 扩展

1 投票
1 回答
973 浏览
提问于 2025-04-16 09:28

我有一个包含多个Person对象的列表,每个对象都有很多字段,我通常会用对象列表的通用视图来进行筛选。每个人可以有多个Comment评论,每条评论都有一个时间和一段文字。最终我想做的是根据日期来筛选评论。

class Person(models.Model):
    name = models.CharField("Name", max_length=30)
    ## has ~30 other fields, usually filtered on as well

class Comment(models.Model):
    date = models.DateTimeField()
    person = models.ForeignKey(Person)
    comment = models.TextField("Comment Text", max_length=1023)

我想要得到一个像这样的查询集:

Person.objects.filter(comment__date__gt=date(2011,1,1)).order_by('comment__date')

然后把这个查询集发送到对象列表中,这样我就能看到按日期排序的评论,并且每页只显示一定数量的对象。

比如,如果“人A”的评论日期是2010年12月12日、2011年1月2日、2011年1月5日,“人B”没有评论,而“人C”在2010年1月3日有一条评论,我希望看到的结果是:

"Person A",   1/2  - comment
"Person C",   1/3  - comment
"Person A",   1/5  - comment

我更希望不需要切换到用Comments.objects.filter()来筛选,因为那样会让我在视图和模板中重复写很多代码。

现在如果我执行以下命令,我会得到一个查询集返回(PersonA, PersonC, PersonA),但如果我在模板中渲染这个查询集,每个人的评论集都会包含他们所有的评论,即使那些评论不在日期范围内。

理想情况下,我希望有某种功能,可以把Person查询集的comment_set扩展成一个更大的查询集,这样可以根据评论进行排序,并放入对象列表的通用视图中。通常在SQL中用JOIN来做这件事很简单,但我不想放弃我在其他地方使用的ORM。


好的,我的解决方案基本上就是使用Comments.objects.filter(); 把模板分成一个单独的文件,以适当的方式包含它,应用额外的上下文布尔值(如果有评论日期过滤,就在视图中所有人名的引用前加上合适的前缀字符串(可能是'',也可能是'person__'):

{% if comment_date_filter %}
   {% for obj in object_list %}
      {% with obj.person as p %}
        {% include "object_list_row.html" %}
      {% endwith %}
   {% endfor %}
{% else %}
   {% for obj in object_list %}
      {% with obj as p %}
        {% include "object_list_row.html" %}
      {% endwith %}
   {% endfor %}
{% endif %}

1 个回答

3

你还有一个选择,就是把所有的对象提取出来,变成 (Person, Date, Comment) 这样的组合,然后在Python里进行排序。

不过,我不太清楚你为什么不想用 Comment.objects.filter() 这个方法。其实这个方法应该会比较快,特别是如果你的日期字段有索引的话。

撰写回答