I have a function with multiple if else statements that I'm trying to simplify in Django

Is there a pattern or maybe a better modeling approach that I could use here?

The idea behind is to have a thumbs up, thumbs down behavior for each blog post


def blog_post_vote(request, slug):
    post = get_object_or_404(BlogPost, slug=slug)
    if request.method == "POST":
        vote = request.POST['vote']
        has_user_voted = BlogPostUserVote.objects.filter(blog_post=post, user=request.user).count()
        if has_user_voted == 0:
            if vote == "yes":
                user_vote_yes = BlogPostUserVote(blog_post=post, user=request.user, vote_yes=1)
            if vote == "no":
                user_vote_no = BlogPostUserVote(blog_post=post, user=request.user, vote_no=1)
            has_user_voted_yes = BlogPostUserVote.objects.filter(blog_post=post, user=request.user, vote_yes=1).count()
            has_user_voted_no = BlogPostUserVote.objects.filter(blog_post=post, user=request.user, vote_no=1).count()
            if vote == "yes" and has_user_voted_yes == 0:
                user_vote_yes = BlogPostUserVote(blog_post=post, user=request.user, vote_yes=1)
                BlogPostUserVote.objects.filter(blog_post=post, user=request.user, vote_no=1).delete()
            if vote == "no" and has_user_voted_no == 0:
                user_vote_no = BlogPostUserVote(blog_post=post, user=request.user, vote_no=1)
                BlogPostUserVote.objects.filter(blog_post=post, user=request.user, vote_yes=1).delete()
    return redirect(request.META['HTTP_REFERER'])


class BlogPost(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    image = models.ImageField(upload_to='images/', blank=True, null=True)
    title = models.CharField(max_length=500)
    # Slug = Short URL Label
    slug = models.SlugField(unique=True)
    content = models.TextField(null=True, blank=True)
    publish_date = models.DateTimeField(
        auto_now=False, auto_now_add=False, null=True, blank=True)
    timestamp = models.DateTimeField(auto_now=True)
    updated = models.DateTimeField(auto_now=True)

    def thumbs_up(self):
        return BlogPostUserVote.objects.filter(blog_post=self).aggregate(Sum("vote_yes"))['vote_yes__sum']

    def thumbs_down(self):
        return BlogPostUserVote.objects.filter(blog_post=self).aggregate(Sum("vote_no"))['vote_no__sum']

    # This line is very important as it maps the objects to the default manager
    objects = BlogPostManager()

    # Ordering Newest to Oldest
    class Meta:
        ordering = ['-publish_date', '-updated', '-timestamp']

    def get_absolute_url(self):
        return f"/blog/{self.slug}"

class BlogPostUserVote(models.Model):
    blog_post = models.ForeignKey(BlogPost, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    vote_yes = models.SmallIntegerField(null=True, blank=True)
    vote_no = models.SmallIntegerField(null=True, blank=True)
  • \$\begingroup\$ What are has_user_voted and friends? Reading the variable name, I would think a boolean True/False. But you keep checking if ==0 instead. \$\endgroup\$
    – Teepeemm
    Dec 26, 2020 at 22:03
  • \$\begingroup\$ Hi, it is a query against the BlogPostUserVote table and if it finds any record with the given filter will return a number greather than 0. Not exactly a boolean though \$\endgroup\$
    – Laycoonz
    Dec 26, 2020 at 22:23
  • 1
    \$\begingroup\$ Your title is too generic. Please read codereview.stackexchange.com/help/how-to-ask . \$\endgroup\$
    – BCdotWEB
    Dec 27, 2020 at 8:41

1 Answer 1


Well finally I ended up with the following, I changed some names to make it more explanatory and the function to respond to an ajax request. However the logic is pretty much the same:

def blog_post_reaction(request, slug):
    post = get_object_or_404(BlogPost, slug=slug)
    if request.is_ajax and request.method == "POST":
        reaction = json.loads(request.body)['vote']
        BlogPostUserReaction.objects.filter(blog_post=post, user=request.user).delete()
        new_user_reaction = BlogPostUserReaction(blog_post=post, user=request.user)
        if reaction == "upvote":
            new_user_reaction.upvote = 1
        if reaction == "downvote":
            new_user_reaction.downvote = 1
        if any((new_user_reaction.upvote, new_user_reaction.downvote)):
    return JsonResponse({'slug': slug, 'upvotes': post.upvote, 'downvotes': post.downvote})

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.