Created
October 18, 2015 16:26
-
-
Save FeroxTL/57e412a48397a12c02b5 to your computer and use it in GitHub Desktop.
django contrib comments template tag for showing comments with pagination
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import six | |
from django import template | |
from django.template.loader import render_to_string | |
from django.conf import settings | |
from django.utils.encoding import smart_text | |
from django.contrib.contenttypes.models import ContentType | |
import django_comments | |
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger | |
from classytags.core import Options | |
from classytags.arguments import ( | |
Argument, MultiKeywordArgument, KeywordArgument, IntegerArgument | |
) | |
from classytags.helpers import AsTag | |
from classytags.exceptions import BaseError | |
from classytags.values import StringValue | |
from classytags.utils import TemplateConstant | |
register = template.Library() | |
@register.tag | |
class ContextCommentForm(AsTag): | |
name = 'render_context_comment_form' | |
options = Options( | |
'for', | |
Argument('model_obj'), | |
IntegerArgument('object_id', required=False, resolve=False), | |
'with', | |
MultiKeywordArgument('extra', required=False), | |
'as', | |
Argument('as_varname', resolve=False, required=False), | |
) | |
def get_value(self, context, model_obj, object_id, extra): | |
if not model_obj: | |
raise RequiredArgumentError('model_obj') | |
return render_to_string( | |
['comments/form.html'], | |
{'form': django_comments.get_form()(model_obj, initial=extra)}, | |
context) | |
class RequiredArgumentError(BaseError): | |
template = '%(argname)s is required' | |
def __init__(self, argname): | |
self.argname = argname | |
class StringKeywordArgument(KeywordArgument): | |
wrapper_class = StringValue | |
def parse(self, parser, token, tagname, kwargs): | |
if self.name in kwargs: # pragma: no cover | |
return False | |
else: | |
key, value = self.parse_token(parser, token) | |
kwargs[self.name] = self.wrapper_class(value) | |
return True | |
def get_default(self): | |
return TemplateConstant(self.default) | |
@register.tag | |
class PaginatedCommentList(AsTag): | |
""" | |
Render the comment list with paginator | |
COMMENTS_PER_PAGE sets default value for comments per page | |
You can also use {% render_paginated_comment_list ... as variable %} | |
Syntax:: | |
{% render_comment_list for [object] [paginate [page=1] [per_page=10]] | |
[with k=v] %} | |
{% render_comment_list for [app].[model] [object_id] %} | |
Example usage:: | |
{% render_paginated_comment_list for object paginate | |
page=request.GET.page with a=2 %} | |
""" | |
name = 'render_paginated_comment_list' | |
options = Options( | |
'for', | |
Argument('model_obj'), | |
IntegerArgument('object_id', required=False, resolve=False), | |
'paginate', | |
StringKeywordArgument('page', required=False), | |
StringKeywordArgument( | |
'per_page', required=False, | |
default=getattr(settings, 'COMMENTS_PER_PAGE', 20)), | |
'with', | |
MultiKeywordArgument('extra', required=False), | |
'as', | |
Argument('as_varname', resolve=False, required=False), | |
) | |
def get_queryset(self, model, ctype, object_pk): | |
qs = self.comment_model.objects.filter( | |
content_type=ctype, | |
object_pk=smart_text(object_pk), | |
site__pk=settings.SITE_ID, | |
) | |
# The is_public and is_removed fields are implementation details of the | |
# built-in comment model's spam filtering system, so they might not | |
# be present on a custom comment model subclass. If they exist, we | |
# should filter on them. | |
field_names = [f.name for f in self.comment_model._meta.fields] | |
if 'is_public' in field_names: | |
qs = qs.filter(is_public=True) | |
if getattr(settings, 'COMMENTS_HIDE_REMOVED', True) and\ | |
'is_removed' in field_names: | |
qs = qs.filter(is_removed=False) | |
return qs | |
@staticmethod | |
def lookup_content_type(token, tagname): | |
try: | |
app, model = token.split('.') | |
return ContentType.objects.get_by_natural_key(app, model) | |
except ValueError: | |
raise template.TemplateSyntaxError( | |
"Third argument in %r must be in the format 'app.model'" % | |
tagname) | |
except ContentType.DoesNotExist: | |
raise template.TemplateSyntaxError( | |
"%r tag has non-existant content-type: '%s.%s'" % | |
(tagname, app, model)) | |
def get_value(self, context, model_obj, object_id, page, per_page, | |
extra): | |
if not model_obj: | |
raise RequiredArgumentError('model_obj') | |
if isinstance(model_obj, six.string_types): | |
content_type = self.lookup_content_type(model_obj, self.name) | |
else: | |
content_type = ContentType.objects.get_for_model(model_obj) | |
object_id = model_obj.id | |
self.comment_model = django_comments.get_model() | |
qs = self.get_queryset(django_comments.get_model(), content_type, | |
object_id) | |
# Paginate comments | |
paginator = Paginator(qs, per_page) | |
try: | |
comments = paginator.page(page) | |
except PageNotAnInteger: | |
comments = paginator.page(1) | |
except EmptyPage: | |
comments = paginator.page(paginator.num_pages) | |
extra.update({ | |
'comment_list': comments, | |
}) | |
return render_to_string(['comments/list.html'], extra, context) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment