Django:NotImplementedError:annotate()+ distinct(fields)未实现 [英] Django: NotImplementedError: annotate() + distinct(fields) is not implemented
问题描述
有2个简单模型:
class Question(TimeStampedModel):
text = models.CharField(max_length=40)
class Answer(TimeStampedModel):
question = models.ForeignKey(Question, related_name='answers')
is_agreed = models.BooleanField()
author = models.ForeingKey(User, related_name='answers')
这是我的问题:
In [18]: Question.objects.count()
Out[18]: 3
我需要使用'is_user_agreed'和'answers_amount'字段注释查询集:
I need to annotate queryset with 'is_user_agreed' and 'answers_amount' fields:
In [18]: user = User.objects.first()
In [19]: qs = Question.objects.annotate(
...: is_user_agreed=Case(
...: When(answers__in=user.answers.filter(is_agreed=True), then=Value(True)),
...: When(answers__in=user.answers.filter(is_agreed=False), then=Value(False)),
...: default=Value(None),
...: output_field=NullBooleanField(),
...: ),
...: ).annotate(answers_amount=Count('answers'))
...: qs.count()
Out[19]: 4
^这里的计数是4,但是我在db中只有3个问题 :(
因此,我尝试使用 distinct()
In [20]: qs.distinct().count()
Out[20]: 4 # but distinct doesn't work
In [21]: qs.distinct('id').count()
在最后一行代码之后,我遇到了这个异常:
And after last line of code I've got this exception:
NotImplementedError: annotate() + distinct(fields) is not implemented.
我也尝试使用此技巧 annotate(Count('id '))。filter(id__count__gt = 1)
但是在这种情况下,我丢失了所有重复的行,并且丢失了qs.count()是2。
But in this case I'm losing all duplicate rows, and qs.count() is 2.
更新:问题是查询集中的行重复。
UPDATE: The problem is duplicated rows in queryset.
解决方案:(弗拉基米尔第二种方法的扩展版本)
SOLUTION: (Extended variant of Vladimir's second approach)
user = User.objects.first()
user_agreed_questions = user.answers.filter(
is_agreed=True).values_list('question_id', flat=True)
user_not_agreed_questions = user.answers.filter(
is_agreed=False).values_list('question_id', flat=True)
Question.objects.annotate(
answer_amount=Count('answers'),
is_user_agreed=Case(
When(id__in=user_agreed_questions, then=True),
When(id__in=user_not_agreed_questions, then=False),
default=None,
output_field=NullBooleanField(),
),
)
推荐答案
尝试
Question.objects.annotate(
answer_amount=Count('answers'),
is_user_agreed=F('answers__is_agreed'),
).order_by('id', '-answers__is_agreed').distinct('id')
如果问题
没有答案
,则 question.is_user_agreed
是 None
。如果问题
至少有一个 answer
和 answer.is_agreed = True
,那么 question.is_agreed
是 True
。否则, is_user_agreed
是 False
。
If question
has no answers
, then question.is_user_agreed
is None
. If question
has at least one answer
with answer.is_agreed=True
, then question.is_agreed
is True
. Otherwise, is_user_agreed
is False
.
agreed_questons = Answer.objects.filter(
is_agreed=True,
).values_list('question_id', flat=True).distinct()
Question.objects.annotate(
answer_amount=Count('answers'),
is_agreed=Case(
When(id__in=agreed_questions, then=True),
When(answers__isnull=True, then=None),
default=False,
output_field=NullBooleanField(),
),
)
agreed_questons
是个问题
中的 id
,其中至少有一个答案
answer.is_agreed = True
。
agreed_questons
is list of id
of questions
, that have at least one answer
with answer.is_agreed=True
.
这篇关于Django:NotImplementedError:annotate()+ distinct(fields)未实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!