Как показать все теги, связанные с публикацией, в списке публикаций, отфильтрованном по тегу, в 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 по умолчанию.
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)