This repository has been archived on 2023-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
python-blog/src/articles/views/html.py
2021-12-31 12:29:13 +01:00

155 lines
5.5 KiB
Python

import operator
from functools import reduce
from typing import Any
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Page
from django.db.models import F, Q, QuerySet
from django.http import HttpRequest
from django.http.response import HttpResponseBase
from django.shortcuts import get_object_or_404
from django.views import generic
from django.views.generic import DetailView
from articles.models import Article, Tag
class BaseArticleListView(generic.ListView):
model = Article
context_object_name = "articles"
paginate_by = 10
main_title = "Blog posts"
html_title = ""
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
context = super().get_context_data(**kwargs)
context["blog_title"] = settings.BLOG["title"]
context["blog_description"] = settings.BLOG["description"]
page_obj: Page = context["page_obj"]
if page_obj.has_next():
querystring = self.build_querystring({"page": page_obj.next_page_number()})
context["next_page_querystring"] = querystring
if page_obj.has_previous():
querystring = self.build_querystring(
{"page": page_obj.previous_page_number()}
)
context["previous_page_querystring"] = querystring
return context
def get_additional_querystring_params(self) -> dict[str, str]:
return {}
def build_querystring(self, initial_queryparams: dict[str, Any]) -> str:
querystring = {
**initial_queryparams,
**self.get_additional_querystring_params(),
}
return "&".join(map(lambda item: f"{item[0]}={item[1]}", querystring.items()))
class PublicArticleListView(BaseArticleListView):
queryset = Article.objects.filter(status=Article.PUBLISHED)
class ArticlesListView(PublicArticleListView):
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
context = super().get_context_data(**kwargs)
home_article = Article.objects.filter(
status=Article.PUBLISHED, is_home=True
).first()
context["article"] = home_article
return context
class SearchArticlesListView(PublicArticleListView):
template_name = "articles/article_search.html"
html_title = "Search"
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
context = super().get_context_data(**kwargs)
context["search_expression"] = self.request.GET.get("s") or ""
return context
def get_queryset(self) -> QuerySet:
queryset = super().get_queryset()
search_expression = self.request.GET.get("s")
if not search_expression:
return queryset.none()
self.html_title = f"Search results for {search_expression}"
search_terms = search_expression.split()
return queryset.filter(
reduce(operator.and_, (Q(title__icontains=term) for term in search_terms))
| reduce(
operator.and_, (Q(content__icontains=term) for term in search_terms)
)
| reduce(
operator.and_, (Q(tags__name__icontains=term) for term in search_terms)
)
).distinct()
def get_additional_querystring_params(self) -> dict[str, str]:
search_expression = self.request.GET.get("s")
if search_expression:
return {"s": search_expression}
return {}
class TagArticlesListView(PublicArticleListView):
tag: Tag
main_title = ""
html_title = ""
def dispatch(
self, request: HttpRequest, *args: Any, **kwargs: Any
) -> HttpResponseBase:
self.tag = get_object_or_404(Tag, slug=self.kwargs.get("slug"))
self.main_title = self.html_title = f"{self.tag.name} articles"
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
context = super().get_context_data(**kwargs)
context["feed_title"] = self.tag.get_feed_title()
context["feed_url"] = self.tag.get_feed_url()
return context
def get_queryset(self) -> QuerySet:
return super().get_queryset().filter(tags=self.tag)
class DraftsListView(LoginRequiredMixin, BaseArticleListView):
queryset = Article.objects.filter(status=Article.DRAFT)
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
context = super().get_context_data(**kwargs)
context["title"] = "Drafts"
context["title_header"] = context["title"]
return context
class ArticleDetailView(DetailView):
model = Article
context_object_name = "article"
template_name = "articles/article_detail.html"
def get_queryset(self) -> QuerySet:
key = self.request.GET.get("draft_key")
if key:
return Article.objects.filter(draft_key=key).prefetch_related("tags")
queryset = super().get_queryset().prefetch_related("tags")
if not self.request.user.is_authenticated:
queryset = queryset.filter(status=Article.PUBLISHED)
return queryset
def get_object(self, queryset: QuerySet | None = None) -> Article:
obj: Article = super().get_object(queryset)
if not self.request.user.is_authenticated:
obj.views_count = F("views_count") + 1
obj.save(update_fields=["views_count"])
return obj
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
kwargs["tags"] = self.object.tags.all()
return super().get_context_data(**kwargs)