Django - vote system

130 views Asked by At

I'm stuck with a simple problem. I want to create a voting system. I have a simple code that doesn't work properly. When I click UP it adds +1, when I click UP again, it removes -1. Same with the DOWN button. The problem is that when I click between the UP and DOWN buttons. The value increases or decreases (indefinitely) - it depends with the click of the button first.

enter image description here

def vote_comment(request):
comment = get_object_or_404(CommentsCode, id=request.POST.get('id'))
is_voted = comment.is_voted.filter(id=request.user.id).exists()
up = request.POST['name'] == "UP"
down = request.POST['name'] == "DOWN"

if up:
    if is_voted:
        comment.is_voted.remove(request.user)
        comment.vote -= 1
        comment.save()
    else:
        comment.is_voted.add(request.user)
        comment.vote += 1
        comment.save()
elif down:
    if is_voted:
        comment.is_voted.remove(request.user)
        comment.vote += 1
        comment.save()
    else:
        comment.is_voted.add(request.user)
        comment.vote -= 1
        comment.save()

template.html

<form action="{% url 'xvote_comment' %}" method="post">
    {% csrf_token %}
    <div id="vov-{{q.pk}}">
        {{q.vote}}
        <button type="submit" id="like" name="UP" value="{{ q.pk }}"
            class="btn btn-danger">!UP</button>
            <button type="submit" id="like" name="DOWN" value="{{ q.pk }}"
            class="btn btn-primary">DOWN</button>
    </div>
</form>

models.py

class CommentsCode(models.Model):
    cpost = models.ForeignKey(CodePost, on_delete=models.CASCADE, null=True, blank=True)
    cauthor = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
    body = models.TextField()
    vote = models.IntegerField(default=0)
    is_voted = models.ManyToManyField(User, related_name='is_voted', blank=True)
    is_approved = models.BooleanField(default=True)

js in template

<script type="text/javascript">
    $(document).ready(function (event) {
        $(document).on('click', '#like', function (event) {
            event.preventDefault();
            var pk = $(this).attr('value');
            var name = $(this).attr('name');
            $.ajax({
                type: 'POST',
                url: '{% url "xvote_comment" %}',
                data: {
                    'id': pk,
                    'name': name,
                    'csrfmiddlewaretoken': '{{ csrf_token }}'
                },
                success: function (response) {
                    $('#vov-' + pk).load(" #vov-" + pk);
                    console.log(response)
                },
                error: function (rs, e) {
                    console.log(rs.responseText);
                },
            });
        });
    });
</script>

EDIT

I finally have the code written, maybe not optimal, but I'm just learning. Thank you for all your help

def vote_comment(request):
    comment = get_object_or_404(CommentsCode, id=request.POST.get('id'))
    is_voted_positive = comment.is_voted_p.filter(id=request.user.id).exists()
    is_voted_negative = comment.is_voted_n.filter(id=request.user.id).exists()
    up = request.POST['name'] == "UP"
    down = request.POST['name'] == "DOWN"


    if up and is_voted_positive:
        comment.is_voted_p.add(request.user)
        comment.is_voted_n.remove(request.user)


    elif up and not is_voted_positive:
        comment.is_voted_p.add(request.user)
        if is_voted_negative:
            comment.is_voted_p.remove(request.user)
            comment.is_voted_n.remove(request.user)
        comment.vote += 1
        comment.save()


    elif up and is_voted_negative:
        comment.is_voted_n.remove(request.user)
        comment.is_voted_p.add(request.user)
        comment.vote += 1
        comment.save()


    elif down and is_voted_positive:
        comment.is_voted_n.add(request.user)
        if is_voted_positive:
            comment.is_voted_p.remove(request.user)
            comment.is_voted_n.remove(request.user)
        comment.vote -= 1
        comment.save()


    elif down and is_voted_negative:
        pass


    elif down and not is_voted_negative:
        comment.is_voted_n.add(request.user)
        if is_voted_positive:
            comment.is_voted_p.remove(request.user)
            comment.is_voted_n.remove(request.user)
        comment.vote -= 1
        comment.save()

and it's look:

enter image description here

1

There are 1 answers

8
raphael On

When you click UP the first time, the is_voted is false, and the else condition occurs and the vote increases by 1. Now the next time, the is_voted will be true, and thus the if statement will be true and the vote will decrement by 1. Perhaps this would work (I did not have a chance to test it):

def vote_comment(request):
    comment = get_object_or_404(CommentsCode, id=request.POST.get('id'))
    is_voted = comment.is_voted.filter(id=request.user.id).exists()
    up = request.POST['name'] == "UP"
    down = request.POST['name'] == "DOWN"

    if not is_voted:
        comment.is_voted.add(request.user)
        if down:
            comment.vote -= 1
        elif up:
            comment.vote += 1
        comment.save()

    # Or might even be easier like this:

    #if not is_voted:
    #    comment.is_voted.add(request.user)
    #    comment.vote = comment.vote + 1 if up else comment.vote - 1
        

EDIT

Based on your template I can see another error. The name attribute is what the request.POST will send as the key, the value is the value that will be sent. So there is NO request.POST['name'], since you have nothing that says name='name'. Try the following:

<form action="{% url 'xvote_comment' %}" method="post">
    {% csrf_token %}
    <div id="vov-{{q.pk}}">
        {{q.vote}}
        <button type="submit" id="like" name="vote" value="UP"
            class="btn btn-danger">!UP</button>
        <button type="submit" id="like" name="vote" value="DOWN"
            class="btn btn-primary">DOWN</button>
    </div>
</form>

Then in your view:

def vote_comment(request):
    comment = get_object_or_404(CommentsCode, id=request.POST.get('id'))
    print(request.POST) # Check to see what is actually being sent
    is_voted = comment.is_voted.filter(id=request.user.id).exists()
    up = request.POST['vote'] == "UP"
    down = request.POST['vote'] == "DOWN"

    if not is_voted:
        comment.is_voted.add(request.user)
        if down:
            comment.vote -= 1
        elif up:
            comment.vote += 1
        comment.save()

    # Or might even be easier like this:

    #if not is_voted:
    #    comment.is_voted.add(request.user)
    #    comment.vote = comment.vote + 1 if up else comment.vote - 1