djangodjango-formsdjango-viewsdjango-validation

django-forms: allow logged in user to submit only one comment per individual post


I have a model Post in which the User can leave a Comment along with a set of ratings. I would like to limit the user comments to only one per post. I'm having trouble setting that up in my view

models

class Comment(models.Model):
    post = models.ForeignKey(Post, related_name="comments")
    user = models.ForeignKey(User, related_name="usernamee")
    ...

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='profile')

class Post(models.Model):
...

views

def add_comment(request, slug):
    post = get_object_or_404(Post, slug=slug)

# I tried wrapping all of the below in an "if" statement, something like
# if request.user.comment.exists(): to check if the user has already
# left a comment on this specific post, but I'm not sure of the right way to perform such a check here.

    if request.method == 'POST':
            form = CommentForm(request.POST or None)
            if form.is_valid():
                comment = form.save(commit=False)
                comment.post = post 
                comment.user = request.user 
                comment.email = request.user.email
                comment.picture = request.user.profile.profile_image_url()

                comment.save()

                messages.success(request, "Thank you for leaving a review!")
                return redirect('blog:post_detail', slug=post.slug)

            else:
                messages.error(request, "Something went wrong! We weren't able to process your review :(")  
        else:
            form = CommentForm()



        template = "blog/post/add_comment.html"
        context = {

            'form': form,
            'post': post,
            #'comment_count': comment_count

            }
        return render(request, template, context)

I am under the impression that all I would need is to wrap the entire form code from my add_comment view in some sort of validation system that checks whether or not the current, logged-in user has already left a comment on that specific post (see comments in view)

Anybody know what a potential solution might be? Or if I'm even doing this the right way?


Solution

  • A possible solution can be to:

    1. Get the current Post comments in view
    2. Filter the comments by your request.user
    3. See if the query returned a non-empty queryset

    Something like:

    from django.core.exceptions import PermissionDenied
    
    
    def add_comment(request, slug):
        post = get_object_or_404(Post, slug=slug)
    
        # Get the comments posted by the user for this post
        user_comments = post.comments.filter(user=request.user)
    
        if request.method == 'POST':
                form = CommentForm(request.POST or None)
    
                # Check if there are any comments posted by the user
                if user_comments:
                    # If there are any, raise an error
                    raise PermissionDenied('You have already commented on this post.') 
    
                if form.is_valid():
                    comment = form.save(commit=False)
                    comment.post = post 
                    comment.user = request.user 
                    comment.email = request.user.email
                    comment.picture = request.user.profile.profile_image_url()
    
                    comment.save()
    
                    messages.success(request, "Thank you for leaving a review!")
                    return redirect('blog:post_detail', slug=post.slug)
    
                else:
                    messages.error(request, "Something went wrong! We weren't able to process your review :(")  
        else:
            form = CommentForm()
    
        template = "blog/post/add_comment.html"
        context = {
            'form': form,
            'post': post
        }
    
        return render(request, template, context)
    

    Of course, you can modify the error raising here, but the main idea is to get the comments and filter them by request.user and see if there are any.