Django:通过几个多值关系进行注释
Django: annote through several multi-valued relationships
Django 1.8 和 1.9,Postgres 数据库。
我有一个 Contest
模型,可以包含许多由 Users
提交的相关 Entry
对象。
class Contest(models.Model):
title = models.CharField(max_length=50)
class Entry(models.Model):
contest = models.ForeignKey(Contest, related_name="entries")
user = models.ForeignKey(settings.AUTH_USER_MODEL)
我想获取所有 Contest
对象的列表,并用 complete
标志进行注释,指示特定 user
是否已为每个 Contest
.
from django.db.models import Case, When, BooleanField, Value
user = User.objects.get(...)
contests = Contest.objects.annotate(
complete=Case(
When(entries__user=user, then=Value(True)),
default=Value(False),
output_field=BooleanField(),
)
)
contests
的预期结果是这样的(对于用户 1):
但是,我得到了重复的元素,具体取决于每个 Contest
上 Entries
的数量(注意比赛 4 和 5):
此时,我尝试将 distinct()
添加到查询集的末尾,但由于考虑了新的 complete
注释,我仍然得到 [=25= 的重复项].
由于我使用的是 Django >= 1.8 并使用 Postgres,所以我想到了使用 distinct("id")
。遗憾的是,这在 Contest 4
.
中设置为 False
这就是我决定 post 这个问题的部分。关于如何从当前结果获得预期结果的任何指示(第一个 table)?我是否通过条件注释大大忽略了某些东西?
您可以同时添加 order_by
和 distinct
以获得您想要的结果。
contests = Contest.objects.annotate(
complete=Case(
When(entries__user=user, then=Value(True)),
default=Value(False),
output_field=BooleanField(),
)
).order_by('id', '-complete').distinct('id')
请注意 distinct
文档中的以下注释
When you specify field names, you must provide an order_by()
in the QuerySet, and the fields in order_by()
must start with the fields in distinct()
, in the same order.
For example, SELECT DISTINCT ON (a)
gives you the first row for each value in column a
. If you don’t specify an order, you’ll get some arbitrary row.
因此,首先按 id
对结果进行排序,然后按 complete
的降序排列(,否则你会得到 complete=False
在顶部)。然后,使用 distinct('id')
保留每个 id
的第一行并删除其他行。
Django 1.8 和 1.9,Postgres 数据库。
我有一个 Contest
模型,可以包含许多由 Users
提交的相关 Entry
对象。
class Contest(models.Model):
title = models.CharField(max_length=50)
class Entry(models.Model):
contest = models.ForeignKey(Contest, related_name="entries")
user = models.ForeignKey(settings.AUTH_USER_MODEL)
我想获取所有 Contest
对象的列表,并用 complete
标志进行注释,指示特定 user
是否已为每个 Contest
.
from django.db.models import Case, When, BooleanField, Value
user = User.objects.get(...)
contests = Contest.objects.annotate(
complete=Case(
When(entries__user=user, then=Value(True)),
default=Value(False),
output_field=BooleanField(),
)
)
contests
的预期结果是这样的(对于用户 1):
但是,我得到了重复的元素,具体取决于每个 Contest
上 Entries
的数量(注意比赛 4 和 5):
此时,我尝试将 distinct()
添加到查询集的末尾,但由于考虑了新的 complete
注释,我仍然得到 [=25= 的重复项].
由于我使用的是 Django >= 1.8 并使用 Postgres,所以我想到了使用 distinct("id")
。遗憾的是,这在 Contest 4
.
False
这就是我决定 post 这个问题的部分。关于如何从当前结果获得预期结果的任何指示(第一个 table)?我是否通过条件注释大大忽略了某些东西?
您可以同时添加 order_by
和 distinct
以获得您想要的结果。
contests = Contest.objects.annotate(
complete=Case(
When(entries__user=user, then=Value(True)),
default=Value(False),
output_field=BooleanField(),
)
).order_by('id', '-complete').distinct('id')
请注意 distinct
When you specify field names, you must provide an
order_by()
in the QuerySet, and the fields inorder_by()
must start with the fields indistinct()
, in the same order.For example,
SELECT DISTINCT ON (a)
gives you the first row for each value incolumn a
. If you don’t specify an order, you’ll get some arbitrary row.
因此,首先按 id
对结果进行排序,然后按 complete
的降序排列(,否则你会得到 complete=False
在顶部)。然后,使用 distinct('id')
保留每个 id
的第一行并删除其他行。