Django:NotImplementedError:annotate()+ distinct(fields)未实现 [英] Django: NotImplementedError: annotate() + distinct(fields) is not implemented

查看:258
本文介绍了Django:NotImplementedError:annotate()+ distinct(fields)未实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆