Question

I have written this signal receiver in django 1.6 that is intended to block posted comments containing bad words from being saved database:

@receiver(pre_save, sender= Comment)
def spam_filter(sender, **kwargs):
    cmnt = kwargs['instance']
    my_expression = '|'.join(re.escape(word) for word in BAD_WORDS)

    if re.search(my_expression, cmnt.body, flags=re.IGNORECASE):    
        #pervent the comment from being saved


    else:
        pass

I am wondering how to tell django in place of '#pervent comment being saved' to not save the 'bad' comment instance?

P.S. the veiw:

@login_required
def add_comment(request, post_id):  

    p= Blog.objects.get(id=post_id)
    post_slug = p.slug
    cform = CommentForm(request.POST)
    if cform.is_valid():
        c = cform.save(commit = False)
        c.created = timezone.now()
        c.post = p
        c.author = request.user
        c.save()
        args=post_slug
        messages.info(request, "comment was added")  
        return HttpResponseRedirect(reverse("Blog.views.post_withslug", 
                                            args=[post_slug]))
Was it helpful?

Solution

Based on your comment of being new to Django I'm going to provide an alternative solution. Try looking for the bad words during form validation. You can check specific form fields by writing a method for a specific field by following this format: def clean_<fieldname>. If your CommentForm has a field name body we can do the following:

from django import forms

class CommentForm(forms.Form):
    # Everything as before.
    ...

    def clean_body(self):
        body = self.cleaned_data['body']
        my_expression = '|'.join(re.escape(word) for word in BAD_WORDS)

        if re.search(my_expression, body, flags=re.IGNORECASE):    
            # prevent the comment from being saved
            raise forms.ValidationError("Wash your mouth out with soap.")

        # Always return the cleaned data, whether you have changed it or
        # not.
        return body

Edit:

Some additional comments after seeing your view.

You should be able to add the def clean_body() function mentioned above to your CommentForm and have it behave as expected. Your view as posted will only respond if form.is_valid() evaluates to True. You'll need to make sure the view can handle if someone has a comment that contains a bad word and form.is_valid evaluates to False. See the sample code here for a typical Django function based view. If after fixing these things you're still having problems post the CommentForm and template code along with any exceptions. Be sure to remove your original signal code.

Replace p = Blog.objects.get(id=post_id) with p = get_object_or_404(Blog, pk=post_id). This way if a user supplies a bad post_id they'll immediately get a 404 instead of an exception being thrown as get() will do if it can't find a single object. Docs on get_object_or_404 here.

You can also save a few lines by having your model automatically add the current time when it is created:

class Comment(models.Model):
    created = models.DateField(auto_add_now=True)

Then you can remove c.created = timezone.now() from the view.

OTHER TIPS

I think you can raise some exception and catch in

try:
    MyModel.objects.save() #or create
except ValidationError:
    do_other_staff

in your code:

if not re.search(my_expression, cmnt.body, flags=re.IGNORECASE): 
    return True

raise ValidationError('this text explains an error')
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top