帮助Django ORM查询

时间:2011-05-16 17:39:54

标签: django orm annotations

我有两个Django模型(简化):

class Movie(models.Model):
    title = models.CharField(max_length=255)
    year = models.IntegerField(max_length=4)
    rating = models.DecimalField(max_digits=2, decimal_places=1, default=0)


class Request(models.Model):
    movie = models.ForeignKey(Movie)
    user = models.ForeignKey(User)
    language = models.CharField(max_length=7, choices=settings.APP_LANGUAGES, db_index=True)
    notes = models.CharField(max_length=255, blank=True, null=True)
    added = models.DateTimeField(default=datetime.now)

我希望每部电影都按语言计算所有请求。我实际上提出了一个带有ORM查询的解决方案,它为我提供了我正在寻找的结果:

reqs = Request.objects.values('movie', 'langauge').annotate(Count('language'))

但是,我将需要访问其他Movie属性,而我将在模板中呈现结果。显然,上面的查询返回ValueQuerySet,如:

[{'movie': 460, 'language__count': 1, 'language': u'es-mx'}, {'movie': 458, 'language__count': 2, 'language': u'cs'}, {'movie': 459, 'language__count': 1, 'language': u'el'}]

因此reqs[0].movie.rating之类的东西不起作用。那么,我该如何访问其他Movie属性呢?

谢谢。

1 个答案:

答案 0 :(得分:1)

您可以这样做:

reqs = Request.objects.values('movie', 'movie__rating', 'movie__title', 'movie__year', 'language').annotate(Count('language'))
print reqs

这里是示例输出:

[
    {'movie__year': 2010, 'language': u'EN', 'movie__title': u'Foo', 'movie': 1, 'language__count': 1, 'movie__rating': Decimal('1')}, 
    {'movie__year': 2010, 'language': u'ES', 'movie__title': u'Foo', 'movie': 1, 'language__count': 1, 'movie__rating': Decimal('1')}, 
    {'movie__year': 2010, 'language': u'RU', 'movie__title': u'Foo', 'movie': 1, 'language__count': 1, 'movie__rating': Decimal('1')}, 
    {'movie__year': 1998, 'language': u'EN', 'movie__title': u'Bar', 'movie': 2, 'language__count': 3, 'movie__rating': Decimal('9')}, 
    {'movie__year': 1998, 'language': u'RU', 'movie__title': u'Bar', 'movie': 2, 'language__count': 1, 'movie__rating': Decimal('9')}, 
]

你可以看到返回额外的电影属性不会改变计数,这里是原始查询的示例输出:

reqs = Request.objects.values('movie', 'language').annotate(Count('language'))
print reqs

这会产生输出:

[
    {'movie': 1, 'language__count': 1, 'language': u'EN'}, 
    {'movie': 1, 'language__count': 1, 'language': u'ES'}, 
    {'movie': 1, 'language__count': 1, 'language': u'RU'}, 
    {'movie': 2, 'language__count': 3, 'language': u'EN'}, 
    {'movie': 2, 'language__count': 1, 'language': u'RU'}, 
]

修改

如果您希望能够在电影上调用方法,那么您希望在查询时选择电影,而不是请求

movies = Movie.objects.annotate(num_lang=Count('request__language')).all()

这将返回所有电影,按请求的语言计数进行注释,您可以通过电影上的属性* num_lang *访问这些电影。您还可以调用电影对象上的所有方法