Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Listing top comments #210

Open
bitFez opened this issue Aug 30, 2020 · 12 comments
Open

Listing top comments #210

bitFez opened this issue Aug 30, 2020 · 12 comments
Assignees
Milestone

Comments

@bitFez
Copy link

bitFez commented Aug 30, 2020

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)

@danirus
Copy link
Owner

danirus commented Aug 31, 2020

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.

@bitFez
Copy link
Author

bitFez commented Aug 31, 2020

Thank you. I'll be looking out for your reply :-)

@danirus
Copy link
Owner

danirus commented Sep 12, 2020

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.

@RealBrionac
Copy link

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 ^^

@danirus
Copy link
Owner

danirus commented Sep 21, 2020

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.

@RealBrionac
Copy link

RealBrionac commented Sep 21, 2020

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'

@danirus danirus pinned this issue Sep 26, 2020
@danirus
Copy link
Owner

danirus commented Sep 26, 2020

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 danirus added this to the 3.0.0 milestone Sep 27, 2020
@RealBrionac
Copy link

RealBrionac commented Sep 28, 2020

@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

danirus added a commit that referenced this issue Dec 10, 2020
The React plugin requires changes to use the new reaction API end point.
@danirus danirus mentioned this issue Dec 20, 2020
@ogurec-ogurec
Copy link

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

@danirus
Copy link
Owner

danirus commented Feb 12, 2021

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.

@ogurec-ogurec
Copy link

Thanks, we'll wait :)
Good luck with your affairs! @danirus

@danirus
Copy link
Owner

danirus commented Feb 17, 2022

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.

@danirus danirus linked a pull request Feb 17, 2022 that will close this issue
@danirus danirus mentioned this issue Feb 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants