我正在尝试按其外键在过去7天内创建的对象数量对查询集进行排序。
如果有三个标题如:
Title one --> total entry: 100, entries in last 7 days: 5
Title two --> total entry: 10, entries in last 7 days: 8
Title three --> total entry: 50, entries in last 7 days: 2
我希望他们订购如下:
Title two > Title one > Title three
这就是我想要获得上述生成器的内容:
all_titles = Title.objects.annotate(
num_entries=Count(
"entry", filter = Q(entry__entry_date2__gte=make_aware(
datetime.datetime.today()-datetime.timedelta(days=7)
)
)
)
).order_by("num_entries")
这就是我的模型:
class Title(models.Model):
title_text = models.CharField(max_length=50, null=True)
title_url = models.CharField(max_length=100, null=True)
title_channels = models.ManyToManyField(TitleChannels)
def __str__(self):
return self.title_text
class Entry(models.Model):
entry_title = models.ForeignKey(Title, on_delete=models.CASCADE)
entry_text = models.CharField(max_length=2500, null=True, blank=True)
entry_author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
entry_date = models.CharField(max_length=20, null=True, blank=True)
entry_points = models.IntegerField(default=0, null=True, blank=True)
entry_readability = models.BooleanField(default=True)
entry_date2 = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.entry_text
我没有按照我想要的顺序排序,而是按照标题entry_set的长度排序。
答案 0 :(得分:1)
请注意,默认情况下order_by
会从较低到较高排序,因此您的订单将是
Title three --> 2 entries in the last week
Title one --> 5 entries in the last week
Title two --> 8 entries in the last week
所以我认为你想按降序排序:.order_by("-num_entries")
我已经创建了一个小型演示,其中的数据非常类似于你的数据,以显示差异:
last_week = datetime.datetime.today() - datetime.timedelta(days=7)
count_last_week = Count(
"entry",
filter=Q(
entry__entry_date2__gte=(
django.utils.timezone.make_aware(last_week)
)
)
)
q = Title.objects.annotate(
entries_last_week=count_last_week
).order_by(
"entries_last_week"
)
for title_entry in q.all():
print(
"%s: %s entries last week (total entries: %s)" % (
title_entry.title_text,
title_entry.entries_last_week,
Entry.objects.filter(entry_title=title_entry).count()
)
)
print('----')
q = Title.objects.annotate(
entries_last_week=count_last_week
).order_by(
"-entries_last_week" # Important '-'
)
for title_entry in q.all():
print(
"%s: %s entries last week (total entries: %s)" % (
title_entry.title_text,
title_entry.entries_last_week,
Entry.objects.filter(entry_title=title_entry).count()
)
)
我在print()
中按标题添加了条目总数,以显示所有值(计数注释)都已正确计算。
Title three: 2 entries last week (total entries: 50)
Title one: 5 entries last week (total entries: 100)
Title two: 8 entries last week (total entries: 10)
----
Title two: 8 entries last week (total entries: 10)
Title one: 5 entries last week (total entries: 100)
Title three: 2 entries last week (total entries: 50)
根据OP的评论/ chat消息编辑:
将过滤器传递给Count()
(或其他注释)的可能性为added in Django 2.0
在Django 1.11.X中你应该仍然可以使用子查询执行此操作:
import datetime
import django.utils.timezone
from django.db.models import OuterRef, Subquery, Count, IntegerField
last_week = django.utils.timezone.make_aware(
datetime.datetime.today() - datetime.timedelta(days=7)
)
entries_last_week_sub_q = Entry.objects.filter(
entry_date2__gte=last_week,
entry_title=OuterRef('pk') # The primary key of the Title objects
# where this subquery will be "embedded"
).values(
'entry_title'
).annotate(
cnt=Count('*')
).values('cnt')[:1]
q = Title.objects.annotate(
entries_last_week=Subquery(entries_last_week_sub_q, output_field=IntegerField()),
).order_by(
'-entries_last_week'
)
print("query %s" % q.query)
print('----')
print("Using subqueries:")
for title_entry in q.all():
print("%s: %s entries last week" % (
title_entry.title_text, title_entry.entries_last_week)
)
在Django 2.0中测试过,不在1.11中...... : - (
灵感来自here,当然还有Django docs。
而且,也许值得查看Title.entry_set
的{{3}},但使用prefetch_related
以便您可以通过提供来缩小要加载的Entry
个对象的范围上周创建的条目查询集?像这样:
q = Title.objects.prefetch_related(
Prefetch('entry_set', queryset=Entry.objects.filter(entry_date2__gte=last_week))
).annotate(
entries_last_week=Count('entry_set),
).order_by(
'-entries_last_week'
)
此方法(与上面几行子查询的示例相反)尚未经过测试。