django-comments-xtd
django-comments-xtd copied to clipboard
How to paginate comments tree
Hello everybody,
I was needing to render the comments with pagination, in the tree form and sorted in this way:
- all the commnents with level = 0 in the descending order
- all the others comments in the ascending order
Maybe it was right in front on me, but I did't find a ready solution to solve my issue, so I decided to try to do it myself. I'm pretty sure that there will be many better ways to get the same result, however it seems that my solution works well.
I added a classmethod to my Comment model
@classmethod
def reverse_tree_from_queryset(cls, queryset, with_flagging=False,
with_feedback=False, user=None):
def deepsort(dic_list, level=0):
if level == 0:
def f(obj): return obj['comment'].thread_id
dic_list.sort(key=f, reverse=True)
else:
def f(obj): return obj['comment'].order
dic_list.sort(key=f)
for d in dic_list:
if d['children']:
deepsort(d['children'], d['comment'].level)
tree = MainComment.tree_from_queryset(
queryset, with_flagging, with_feedback, user)
deepsort(tree)
return tree
Then I created a mixins following this approch https://docs.djangoproject.com/en/2.1/topics/class-based-views/mixins/#using-singleobjectmixin-with-listview
from django.db.models import Subquery
from django.views.generic import ListView
from django.contrib.contenttypes.models import ContentType
from django_comments_xtd.conf import settings
from .models import MainComment
class CommentListMixin(ListView):
reverse = True
def get_paginator(self, queryset, page_size, orphans, allow_empty_first_page, **kwargs):
return super(CommentListMixin, self).get_paginator(
self.get_tree_queryset(queryset),
page_size,
orphans=orphans,
allow_empty_first_page=allow_empty_first_page,
**kwargs
)
def get_queryset(self):
if hasattr(self.object, 'comments'):
return self.object.comments.filter(is_removed=False, level=0)
else:
obj = self.object
ctype = ContentType.objects.get_for_model(obj)
return MainComment.objects.filter(
content_type=ctype,
object_pk=obj.pk,
site__pk=settings.SITE_ID,
is_removed=False,
level=0
)
def get_tree_queryset(self, queryset):
if hasattr(self.object, 'comments'):
qs = self.object.comments.filter(
parent_id__in=Subquery(queryset.values('pk'))
)
else:
obj = self.object
ctype = ContentType.objects.get_for_model(obj)
qs = MainComment.objects.filter(
content_type=ctype,
object_pk=obj.pk,
site__pk=settings.SITE_ID,
is_removed=False,
level=0
)
if self.reverse:
return MainComment.reverse_tree_from_queryset(
qs, user=self.request.user)
else:
return qs
Lastly I use my mixin in this way:
class CategoryWithComments(CommentListMixin, SingleObjectMixin):
paginate_by = 5
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Category.objects.all())
return super(CategoryWithComments, self).get(request, *args, **kwargs)
Regards, Fabio