Django CBVs: повторное использование запроса из get_queryset в методе get_context_data в ListView
Мне нужно передать в шаблон объект Tag, но без дополнительного запроса к базе данных в методе get_context_data.
Подскажите, пожалуйста, есть ли более элегантный способ получить значение из метода get_queryset в get_context_data.
И если есть более элегантный способ, то корректно ли объявлять собственные поля в представлениях Django
class PostListView(ListView):
model = Post
paginate_by = 3
context_object_name = 'posts'
template_name = 'blog/post/list.html'
tag = None
def get_queryset(self):
data = super().get_queryset()
if tag_slug := self.kwargs.get('tag_slug'):
self.tag = get_object_or_404(Tag, slug=tag_slug)
data = data.filter(tags__in=[self.tag])
return data
def get_context_data(self, *, object_list=None, **kwargs):
data = super().get_context_data(**kwargs)
data['tag'] = self.tag
return data
get queryset должен только подготовить queryset без попадания в базу данных. В вашем случае вы делаете много не нужных вещей:
def get_queryset(self):
query = Q()
if self.kwargs.get('tag_slug'):
query = Q(tags__slug=self.kwargs['tag_slug'])
return super().get_queryset().filter(query).select_related('tag')
в действительности функция выше - это One-liner. Вам не нужен никакой тег в контексте, но если вы хотите:
def get_context_data(self, *args, **kwargs):
response = super().get_context_data(*args, **kwargs)
if len(response['object_list']) : # only one hit in database
response['tag'] = response['object_list'][0].tag
else:
raise Http404
return response
len сделал запрос в базу данных, и получил все объекты.
На основании ответа я отредактировал свой код следующим образом:
поскольку мне нужно имя тега и оно может отличаться от tug slug, я переопределяю метод get, чтобы получить объект тега и не выполнять код uselees позже
удален запрос из get_queryset
заменил "object_list" на "posts" из-за итерации через посты в моем шаблоне
class PostListView(ListView): model = Post paginate_by = 3 context_object_name = 'posts' template_name = 'blog/post/list.html' tag = None def get(self, request, *args, **kwargs): if tag_slug := self.kwargs.get('tag_slug'): self.tag = get_object_or_404(Tag, slug=tag_slug) return super(PostListView, self).get(request, *args, **kwargs) def get_queryset(self): query = Q() if self.tag: query = Q(tags__slug=self.tag) return super(PostListView, self).get_queryset().filter(query) def get_context_data(self, *args, **kwargs): response = super().get_context_data(*args, **kwargs) if len(response['posts']): response['tag'] = self.tag else: raise Http404 return response