django-comments-xtd
django-comments-xtd copied to clipboard
Listing top comments
I've tried implementing this from the view without success and I was wondering if such a feature existed. I want to list top 5 comments for example on an object.
This clearly didn't work :-(
top_Comments = django_comment_flags.objects.filter(flag=="I like it").filter(flag.count>=1)
It's not implemented in the app, but it would be a nice to have feature. I will try to draft a possible solution later today. So far I can only confirm that it's not easy.
Thank you. I'll be looking out for your reply :-)
I can't come up with any medium cost solution.
The fact that I use CommentFlag
for the like/dislike reactions complicates it a lot.
Maybe having a OneToOne relation with another model to keep counters updated asynchronously would be a solution.
I will think about it. There have been already many issues reported on how to ease this sort of queries.
If you have another idea in mind, please share it, having a few ideas will help to figure the solution.
Quick question Danirus: Why did you decide to use the CommentFlag system for the likes and dislikes?
It might be a stupid idea, but what is the issue with simply having a field in the Comment model containing all the users who liked/disliked the comment. It seems to me that it would make all these filtering much easier.
Is it too slow maybe?
Let me know what you think ^^
The limitation from using CommentFlag
was known since the beginning. At the time I started developing this application database engines didn't have support for JSON fields or they were not queryable. With Django 3.1 that has changed, and it can be implemented in a different way. Backward compatibility has to be considered too. Using a JSONField in XtdComment
is a good option. Another option is to use a OneToOne relationship to a Reaction
model, to keep the number of likes/dislikes along with additional reactions. The list of users associated to each reaction is also a must have.
The operation that happens the most is to retrieve the comments and its reactions. Ideally that would have to happen without making SQL JOINs to consume as less DB resources as possible. Posting reactions happens less often but it is significant and should happen without complicated queries too.
This issue is a top priority. Please, don't hesitate to post your ideas and concerns about it. I'll be glad to read and consider them.
I see. I will try to implement a clean OneToOne relationship since I might need other reactions in the future. I'll tell you how it goes.
Thanks a lot for the library btw, it's great!
Edit: Actually wouldn't it be even better to user ManyToMany relationships with the user base? Something like this:
class Reaction(models.Model):
comment = models.OneToOneField(XtdComment, unique = True, related_name = 'reactions', on_delete=models.CASCADE)
likers = models.ManyToManyField(User, related_name = 'likers')
dislikers = models.ManyToManyField(User, related_name = 'dislikers')
flaggers = models.ManyToManyField(User, related_name = 'flaggers')
def __str__():
self.comment.name + ' reactions'
I prefer a different model to cover slightly different requirements:
- To be able to react to comments not only with like or dislike but to allow other library customizable reactions. By default it could provide like and dislike but other cases might require Laugh, Hooray, Confused, Heart, Rocket and Eyes, as this GitHub comments do.
- To have immediate access to how many of those flags a comment has.
- To have immediate access to the list of users who reacted so to the comment. So, yes, ManyToMany here is a requirement.
The Model I have in mind is this one:
class CommentReaction(models.Model):
reaction = models.CharField(_('reaction'), max_length=30, db_index=True)
comment = models.ForeignKey(XtdComment,
verbose_name=_('reactions'),
related_name="reactions",
on_delete=models.CASCADE)
counter = models.IntegerField(default=0)
authors = models.ManyToManyField(settings.AUTH_USER_MODEL)
# Constants for reaction types.
LIKED_IT = "I liked it"
DISLIKED_IT = "I disliked it"
I have pushed this changes to the branch issue-210, check the details in this diff. The like and dislike controllers in the views.py module do work already. Can be tested with the comp example project, with the quotes app.
@RealBrionac, are you working on a fix to this issue, planning to send a PR? :-)
@danirus I'm in the process of adapting the library to fit the need of my current application (mainly adding ajax functions to make everything dynamic with no page refresh, and changing the models). Once it's ready and clean I can upload it on another repo , or try to make it backward compatible and send you a PR
please tell, is it possible to make all comments to the object (Post, for example) show already in ascending order from the most popular (from most pluses to the smallest)? @danirus
With version 2.8 is not possible. With v3.0 it is, but it's not ready yet, you could play with it in the branch rel-3.0.0.
There is a new CommentReaction
model that is better for aggregation (as described here). With v3.0 it's possible to do something like this:
from django.db.models import Q
from django_comments_xtd.models import ReactionEnum, XtdComment
cond = Count('reactions', filter=Q(reactions__reaction=ReactionEnum.LIKE_IT))
queryset = XtdComment.objects.annotate(num_likes=cond).order_by('-num_likes')
That queryset will give you a descending list of comments by the number of likes a comment has received.
I'm sorry it's not done yet. On top of my work load the corona crisis is not helping. I'll get there with a little luck no later than the end of April.
Thanks, we'll wait :) Good luck with your affairs! @danirus
Just for the record, to get the 5 comments with more "Like" reactions posted to a given content_type=16
(it corresponds to content_type.app_label="stories"
, content_type.model="story"
) , using the demo project demos/project-stories
(set it up following instruction in its README.md file), as it is already implemented in the branch rel-3.0.0
, you could do the following from within the project-stories/project_stories
directory, with the virtualenv psenv
activated:
$(psenv) project_stories $ python manage.py shell
>>> from django_comments_xtd.models import CommentReaction
>>> from project_stories.enums import ReactionEnum
>>> [
(obj.comment.id, obj.counter) for obj in CommentReaction.objects.filter(
reaction=ReactionEnum.LIKE_IT, comment__content_type=16, comment__object_pk=3
).order_by('-counter', 'comment__level')[:5]
]
[(881, 6), (899, 5), (890, 5), (868, 4), (866, 3)]
There might be many comments with at least 3 LIKE_IT
reactions, so in order to consider first those comments with less nesting level I add 'comment__level'
to the order_by
clause.
If you run the project-stories
demo, you can check that those comments (881
, 899
, 890
, 868
and 866
), posted to the story "Colonies in space may be only hope, says Hawking", are the ones that have received more LIKE_IT
reactions.