Django запрос, аннотирование цепочки связанных моделей

У меня есть следующая схема с PostgreSQL.

class Video(models.Model):
    title = models.CharField(max_length=255)
    created_at = models.DateTimeField()
    disabled = models.BooleanField(default=False)
    view_count = DecimalField(max_digits=10, decimal_places=0)

class TopVideo(models.Model):
    videos = (Video, on_delete=models.CASCADE, primary_key=True)

class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    video = models.ForeignKey(Video, related_name="comments", on_delete=models.CASCADE)

Причина, по которой у меня есть модель TopVideo, заключается в том, что у меня миллионы видео, и запрос к ним занимает много времени на дешевом сервере, поэтому у меня есть вторичная модель, которая заполняется задачей celery, промывается и заново заполняется при каждом запуске, что делает время загрузки домашней страницы намного быстрее. Задача выполняет запросы, которые вы видите далее, и сохраняет их в модели TopVideo. Таким образом, задача может выполняться долго, но пользователю больше не нужно ждать дорогостоящего запроса.

До использования модели TopVideo я выполнял такой запрос для своей домашней страницы:

     videos = (
         Video.objects.filter(created_at__range=[start, end])
         .annotate(comment_count=Count("comments"))
         .exclude(disabled=True)
         .order_by("-view_count")[:100]
     )

Это прекрасно работало, и у меня был доступ к "comment_count" в моем шаблоне, где я мог легко показать количество комментариев для каждого видео.

Но теперь, когда я делаю этот запрос:

top_videos = (
    TopVideo.objects.all().annotate(comment_count=Count("video__comments"))
        .select_related("video")
        .order_by("-video__view_count")[:100]
)

и с помощью простого цикла for,

videos = []
for video in top_videos:
    videos.append(video.video)

Я отправляю видео в шаблон для рендеринга. Моя проблема в том, что у меня больше нет доступа к "comment_count" внутри шаблона, и естественно поэтому; я больше не отправляю кверисет. Как я могу получить доступ к comment_count?

То, что я пробовал:

  1. Sending the TopVideo query to template did not work. They're a bunch of TopVideo objects, not Video objects.
  2. I added this piece of code in my template "{{ video.comments.count }}" but this makes 100 requests to the database, which is not really optimal.

Вы можете установить .comment_count на ваши Video объекты с помощью:

videos = []
for top_video in top_videos:
    video = top_video.video
    video.comment_count = top_video
    videos.append(video)

но, несмотря на это, мне неясно почему вы запрашиваете TopVideo, если вы практически вычеркнули TopVideo контекст из видео.

Если вы хотите получить Videos, для которых существует объект TopVideo, вы можете работать с:

videos = Video.objects.filter(
    created_at__range=[start, end], topvideo__isnull=False
).annotate(
    comment_count=Count('comments')
).exclude(disabled=True).order_by('-view_count')[:100]

Таким образом, topvideo__isnull=False будет отфильтровывать Video, которые не являются TopVideos.

Вернуться на верх