from django.conf import settings
from django.contrib.auth.mixins import UserPassesTestMixin
from django.db.models import Count, Q
from django.http import Http404, HttpResponseBadRequest
from django.views.generic import ListView
from django.views.generic.detail import SingleObjectMixin
from django.urls import reverse
from django.views import View
from dal import autocomplete
from taggit.models import Tag
from ..models import Article
from .mixins import ArticleFilterAbstractView
try:
from view_breadcrumbs import BaseBreadcrumbMixin
except ImportError:
from .mixins import NoOperationBreadcrumMixin as BaseBreadcrumbMixin
[docs]
class DisabledTagIndexView(View):
"""
A very basic view which always return the common Http404 page.
"""
def get(self, request, *args, **kwargs):
raise Http404()
[docs]
class EnabledTagIndexView(BaseBreadcrumbMixin, ArticleFilterAbstractView, ListView):
"""
List of tags that are related from at least one article.
"""
model = Tag
template_name = "lotus/tag/list.html"
paginate_by = settings.LOTUS_TAG_PAGINATION
context_object_name = "tag_list"
crumb_title = settings.LOTUS_CRUMBS_TITLES["tag-index"]
crumb_urlname = "lotus:tag-index"
lotus_stage = "tags"
@property
def crumbs(self):
return [
(self.crumb_title, reverse(self.crumb_urlname)),
]
[docs]
def get_queryset(self):
"""
Build complex queryset to get all tags which have published articles.
Published articles are determined with the common publication criterias.
"""
publication_criterias = self.build_article_lookups(
language=self.get_language_code(),
prefix="article__",
)
return Tag.objects.annotate(
article_count=Count(
"article",
filter=Q(*publication_criterias),
)
).filter(article_count__gt=0).order_by("name")
[docs]
class TagDetailView(BaseBreadcrumbMixin, ArticleFilterAbstractView,
SingleObjectMixin, ListView):
"""
Tag detail and its related article list.
Opposed to article or category listing, this one list objects for language from
request, not from the tag language since it dont have one.
"""
model = Tag
listed_model = Article
template_name = "lotus/tag/detail.html"
paginate_by = settings.LOTUS_ARTICLE_PAGINATION
context_object_name = "tag_object"
slug_field = "slug"
slug_url_kwarg = "tag"
pk_url_kwarg = None
crumb_title = None # No usage since title depends from object
crumb_urlname = "lotus:tag-detail"
lotus_stage = "tags"
@property
def crumbs(self):
details_kwargs = {
"tag": self.object.slug,
}
index_crumb_url = (
reverse(EnabledTagIndexView.crumb_urlname)
if settings.LOTUS_ENABLE_TAG_INDEX_VIEW
else None
)
return [
(EnabledTagIndexView.crumb_title, index_crumb_url),
(str(self.object), reverse(self.crumb_urlname, kwargs=details_kwargs)),
]
[docs]
def get_queryset_for_object(self):
"""
Build queryset base to get Tag.
"""
return self.model.objects
[docs]
def get_queryset(self):
"""
Build queryset base to list Tag articles.
Depend on "self.object" to list the Tag related objects.
"""
q = self.apply_article_lookups(
self.listed_model.objects.filter(
tags__id__in=[self.object.id]
),
self.get_language_code(),
)
return q.order_by(*self.listed_model.COMMON_ORDER_BY)
def get(self, request, *args, **kwargs):
# Try to get Tag object
self.object = self.get_object(queryset=self.get_queryset_for_object())
# Let the ListView mechanics manage list pagination from given queryset
return super().get(request, *args, **kwargs)
[docs]
class TagAutocompleteView(UserPassesTestMixin, autocomplete.Select2QuerySetView):
"""
View to return JSON response for a tag list.
Default returns paginated list of all available tags. If request argument ``q`` is
given, the list will return tag items that start with text from argument.
Worth to notice this is language agnostic, since a Tag does not have any specific
language.
"""
[docs]
def test_func(self):
"""
Limit to admin only
"""
return self.request.user.is_staff
[docs]
def get_queryset(self):
qs = Tag.objects.all()
if self.q:
qs = qs.filter(name__istartswith=self.q)
return qs.order_by("name")
[docs]
def post(self, request, *args, **kwargs):
"""
POST request is forbidden since DAL would create a tag for a missing value.
"""
return HttpResponseBadRequest()
TagIndexView = type("TagIndexView", (
(EnabledTagIndexView,)
if settings.LOTUS_ENABLE_TAG_INDEX_VIEW
else (DisabledTagIndexView,)
), {})
"""
This is the effective index class view which inherit either from the working index view
or the dummy 404 view if Tag index is enabled or not according to settings.
"""