Как показать все теги, связанные с публикацией, в списке публикаций, отфильтрованном по тегу, в Django?

Рассмотрите следующие модели:

# models.py

from django.db import models

class Tag(models.Model):
    name = models.CharField()
    number_of_publications = models.PositiveIntegerField()


class Publication(models.Model):
    text = models.TextField()
    tags = models.ManyToManyField(Tag)
# urls.py

from .views import publications_tagged

urlpatterns = [
    path('/questions/tagged/<str:name>', publications_tagged)
]
# views.py

from .models import Tag, Publication
from django.shortcuts import get_object_or_404, render


def publications_tagged(request, name):
    tag = get_object_or_404(Tag.objects.prefetch_related('tags_set'), name=name)
    return render(request, 'myapp/tagged_questions.html', {'tag': tag})

Ок, итак, когда мы переходим к шаблону и делаем цикл for, который создаст представление каждой публикации и покажет соответствующие теги, Django сделает вызов базы данных для каждой публикации, чтобы получить все теги, которые есть у публикации, что означает:

Итерация x из tag.tags_set -> проверьте, какие теги совпадают с publication X.

Конечно, мы можем просто не показывать теги и все будет работать как по волшебству (используя prefetch_related), но это не то, чего мы хотим :)

Как можно сделать что-то подобное в Django?

Мы хотим получить какой-то оптимизированный способ для достижения такого результата, потому что stackoverflow отображает 15 элементов очень быстро, что заставляет меня думать, что они не делают это по-обезьяньи, как Django по умолчанию.

Вот как может выглядеть html

P.S. Моя проблема звучит не совсем так. Но на всякий случай, если кто-то скажет: "О, это плохой дизайн, так вообще нельзя делать", я решил показать пример.

Вы можете добавить свойство к вашей модели Publication для отображения tags в виде списка строк, так:

class Publication(models.Model):
    text = models.TextField()
    tags = models.ManyToManyField(Tag)

    @property
    def tags_list(self):
        # renders as ["django", "python", ...]
        return list(self.tags.values_list("name", flat=True))

Обязательно используйте prefetch_related("tags") для оптимизации запроса.

Ответ очень прост, все, что вам нужно сделать, это в prefetch_related указать publications__tags, что оставляет вам

tag = get_object_or_404(Tag.objects.prefetch_related('publications', 'publications__tags'), name=name)

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