• Author:
  • Published: Oct 21st, 2006
  • Comments: 16

Comment and Karma functions in the Django framework

karma_Someone contacted me concerning a previous post I did on this blog. He could not make work the karma part, and had some strange errors.

My problem was, I did not actually implement anything of what I wrote about, so I took the code of my blog and started modifying it. And I made it work.

The first thing I did was to make the comments work. This was surprisingly easy. If you managed to make FreeComment work, for example by following this tutorial , then you only have to change a few lines. To make things easier, I will change the code of this tutorial so we work over a common and known ground:

  • I suppose that your FreeComment work, so you don’t have to update your urls.py nor the settings.py.
  • Change all lines with the word free and take it out. So, get_free_comment_list becomes get_comment_list and get_free_comment_count would becomes get_comment_count.
  • Copy&paste the freeform.html to form.html and free_preview.html to preview.html.
  • Edit the preview.html and change the following parts:
    • <form action=”../postfree/” method=”post”> becomes <form action=”../post/” method=”post”>.
    • Remove any reference to comment.person_name. Comments are posted by known users and do not need a person_name field. Thus, delete the lines:
      • Posted by {{ comment.person_name }}
      • <p><label for=”id_person_name”>Your name:</label> {{ comment_form.person_name }}</p> {% if comment_form.person_name.errors %}{{ comment_form.person_name.html_error_list }}{% endif %}
  • Edit the form.html and change the following parts:
    • <form action=”/comments/postfree/” method=”post”> becomes <form action=”/comments/post/” method=”post”>.
    • Remove <label for=”id_person_name”>Your name:</label> {{ comment_form.person_name }}

And that’s all. Congratulations, you are the happy owner of a Comment blog/gallery/whatever!

Of course, you can further improve this. You can add a title to the comments, the IP they came from, the time they where done, know if they are public, or if they should be removed… have a look at the Comment model to know more about the possibilities.

Now, we are getting to the problem our friend had. How to make the Karma work in Django?

Again, Django surprises me by how simple it is to use. There is a few steps for doing this.

First, create the /comments/karma_vote_accepted.html template. This will have a message saying (oh! surprise!) that the karma vote has been accepted :-)

Something like this should do:

{% extends "base_site.html" %}

{% block content %}
  <div id="wide">
    Your karma's vote for {{ comment.person_name }}'s comment has been accepted.
  </div>
{% endblock %}
Then, we will add the voting URLs to our code. We want to put it in the same place the comments of a given object are displayed:
{% get_free_comment_list for blog.entry object.id as comment_list %}

<h2 id="comments">Comments</h2>
{% for comment in comment_list %}
  <div class="comment_{% cycle odd,even %}" id="c{{ comment.id }}">
    <span class="comnum"><a id="c{{ comment.id }}" href="http://www.guindilla.eu/admin/blog/post/comment-and-karma-functions-django-framework/#c{{ comment.id }}">#{{ forloop.counter }}</a></span>
    <p><b>{{ comment.person_name }}</b> commented, on {{ comment.submit_date|date:"F j, Y" }} at {{ comment.submit_date|date:"P" }}:</p>
    {{ comment.comment|escape|urlizetrunc:40|linebreaks }}
    <p><a href="/comments/karma/vote/{{ comment.id }}/up/">Give karma</a> or <a href="/comments/karma/vote/{{ comment.id }}/down/">take karma</a>.</p>
  </div>
{% endfor %}

That’s it. But let’s make it better. Now we are going to display the total amount of karma for a comment, with how many positive and negative karma each comment has. Again, it’s a one-line solution:

    {{ comment.comment|escape|urlizetrunc:40|linebreaks }}
    <p>This comment has {{ comment.get_karma_total }} points of karma, {{ comment.get_good_karma_total }} positive and {{ comment.get_bad_karma_total }} negative.</p>
    <p><a href="/comments/karma/vote/{{ comment.id }}/up/">Give karma</a> or <a href="/comments/karma/vote/{{ comment.id }}/down/">take karma</a>.</p>

So now it should work. Launch the web server, try it… and it doesn’t. I got an ‘KarmaScoreManager’ object has no attribute ‘objects’ error.

There are indeed a few bugs in the code. Right now, I have sent a message to the django-developers community to confirm if those are really bugs or a misunderstanding of the code. The facts are, I have tested the patch, Tim Baxter has tested it as well (thanks!!) and it seems to work for us.

So, here is the patch:

Index: contrib/comments/models.py

===================================================================

--- contrib/comments/models.py	(revision 3910)

+++ contrib/comments/models.py	(working copy)

@@ -133,7 +133,7 @@

     def _fill_karma_cache(self):
         "Helper function that populates good/bad karma caches"
         good, bad = 0, 0
-        for k in self.karmascore_set:
+        for k in self.karmascore_set.all():
             if k.score == -1:
                 bad +=1
             elif k.score == 1:
@@ -151,9 +151,8 @@

         return self._karma_total_bad

     def get_karma_total(self):
-        if not hasattr(self, "_karma_total_good") or not hasattr(self, "_karma_total_bad"):
-            self._fill_karma_cache()
-        return self._karma_total_good + self._karma_total_bad
+        self._fill_karma_cache()
+        return self._karma_total_good - self._karma_total_bad

     def get_as_text(self):
         return _('Posted by %(user)s at %(date)s\n\n%(comment)s\n\nhttp://%(domain)s%(url)s') % \
@@ -209,7 +208,7 @@

 class KarmaScoreManager(models.Manager):
     def vote(self, user_id, comment_id, score):
         try:
-            karma = self.objects.get(comment__pk=comment_id, user__pk=user_id)
+            karma = self.get(comment__pk=comment_id, user__pk=user_id)
         except self.model.DoesNotExist:
             karma = self.model(None, user_id=user_id, comment_id=comment_id, score=score, scored_date=datetime.datetime.now())
             karma.save()

With this patch applied, you should have no problems giving karma to any comment of your site.

Now comes the big question: If you did it, why is it not in your site? Well… simply because I do not have enough traffic (yet?) to make it worth :-)

Enjoy!

Update 23 Oct 2006:

A conceptual problem peopl
e might have:

Each user can have one and only one vote per comment.

So, if the karma is 0 and you make a positive vote, the result will be 1.
But then, if you change your vote to -1, well, the total will be -1 :-)
Indeed, if you vote with the same user, the comment will not have 2
votes, 1 and -1. But only one vote, either the 1 or the -1.

If we try to give one positive and one negative karma votes with different
users, we’ll (hopefully…) see that the result is zero.

Tags:

16 Responses to “Comment and Karma functions in the Django framework”


  1. smoon
    on Nov 12th, 2006
    @ 00:15

    Wow, thanks for writing this down. Could come in handy some time :)


  2. Automatthias
    on Nov 30th, 2006
    @ 01:30

    Guillermo, thanks a lot for your excellent guide! I’ve managed to get comments with karma working in one evening.


  3. Silas
    on Dec 31st, 2006
    @ 04:32

    good tutorial thanks a lot


  4. mike
    on Jun 5th, 2007
    @ 17:17

    very helpful


  5. AVL
    on Jun 6th, 2007
    @ 00:02

    I love you dude! Great work and thank you very much for the patch :)

    btw. @the latest svn-developer-release there´s no need to change this line:
    - karma = self.objects.get(comment__pk=comment_id, user__pk=user_id)
    + karma = self.get(comment__pk=comment_id, user__pk=user_id)


  6. Guille
    on Jun 6th, 2007
    @ 09:16

    Thanks both for your comments! Happy it has been of help.


  7. jballard
    on Jun 7th, 2007
    @ 04:25

    Haha, looks like you could use karma in your comments now :) I’d love to help mod down that spam for you.

    But anyway, very useful guide!

    One small typo:
    “Copy&paste the freeform.html to free.html …” should be:
    “Copy&paste the freeform.html to form.html …”.
    But that said, I noticed that in latest SVN revision there is a nice form.html already included. I’d suggest people start with that as it has stuff for handling users not logged in, and some photo posting code, etc.


  8. Visitor021
    on Aug 2nd, 2007
    @ 02:35

    I have visited your site 256-times


  9. Guille
    on Aug 2nd, 2007
    @ 10:37

    That is a round a nice number :-)

    I am pleased to see such interest, but a bit concerned not to fully understand your comment.


  10. usul
    on Jan 5th, 2008
    @ 19:54

    Thanks for this, very helpful

    Question..
    After voting, it defaults to the comments/karma_vote_accepted.html template, is there an easy way to change this? It would be nice to just return to the page where the voting was done or ultimately have this all done and updated via ajax (digg style).


  11. Guille
    on Jan 5th, 2008
    @ 22:28

    Hi,

    To be honest there’s a while I don’t have a look to the code, and that I don’t play with django, so take this with a pinch of salt.

    I’ve seen that there’s not many changes to the karma code. I can not think of any easy way besides changing the karma.py view in contrib/comments/views/ or taking this view as an example and rewrite your own.

    But I am no HTML nor AJAX expert, so I’ll stop here before confusing you!


  12. james
    on Jan 12th, 2008
    @ 22:10

    Thanks for the note, it helped me move from a FreeComment setup to registerd User Comments. Only one other change I had to do in addition to your little outline at the beginning: change comment.person_name to comment.user in my templates

    Thanks again!


  13. Michael
    on Mar 21st, 2008
    @ 20:35

    Thank you very much for this, it was a big help!

    I’ll mention that the typo mentioned in comment #7 above is still in write up. It’s not a big deal (I also noticed it) but it might screw up someone who is not careful.

    Cheers!


  14. Guille
    on Mar 21st, 2008
    @ 23:00

    You are so right… it is corrected now.

    Thanks!


  15. Guindilla — Comment and Karma functions in the Django framework | Invisible Inkling
    on Jan 14th, 2011
    @ 15:38

    [...] Guindilla — Comment and Karma functions in the Django framework [...]


  16. Django Tutorials index « Roshan Book
    on Nov 30th, 2011
    @ 11:52

    [...]  Use of Comment and Karma functions [...]

Leave a Reply

© 2006,2007,2008,2009,2010 Guillermo Fernández Castellanos | Header images by Nick Lobeck