Помощь с запросом Django ORM - PullRequest
2 голосов
/ 16 мая 2011

У меня есть две модели 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'))

Однако мне понадобится доступ к другим атрибутам фильма, пока я буду отображать результаты в шаблоне. Очевидно, что приведенный выше запрос возвращает 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 не будет работать. Итак, как мне получить доступ к другим атрибутам фильма?

Спасибо.

1 Ответ

1 голос
/ 17 мая 2011

Вы можете сделать что-то вроде этого:

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 * в фильме.Вы также сможете вызывать все методы объектов кино

...