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
views.py
@login_required
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)
user_vote_yes.save()
if vote == "no":
user_vote_no = BlogPostUserVote(blog_post=post, user=request.user, vote_no=1)
user_vote_no.save()
else:
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)
user_vote_yes.save()
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)
user_vote_no.save()
BlogPostUserVote.objects.filter(blog_post=post, user=request.user, vote_yes=1).delete()
return redirect(request.META['HTTP_REFERER'])
models.py
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)
@property
def thumbs_up(self):
return BlogPostUserVote.objects.filter(blog_post=self).aggregate(Sum("vote_yes"))['vote_yes__sum']
@property
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)
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:
@login_required
@csrf_exempt
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)):
new_user_reaction.save()
return JsonResponse({'slug': slug, 'upvotes': post.upvote, 'downvotes': post.downvote})
has_user_voted
and friends? Reading the variable name, I would think a booleanTrue
/False
. But you keep checking if==0
instead. \$\endgroup\$