【问题标题】:How to tell django not to save an instance in database?如何告诉 django 不要在数据库中保存实例?
【发布时间】:2024-01-11 20:50:01
【问题描述】:

我在 django 1.6 中编写了这个信号接收器,旨在阻止已发布的包含坏词的 cmets 被保存数据库:

@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

我想知道如何告诉 django 代替“保存#pervent 评论”而不保存“坏”评论实例?

附:观点:

@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]))

【问题讨论】:

  • 为什么在清理表单域时选择使用信号而不是编写这个逻辑?
  • @ScottWoodall 我是 django 新手,你提出了一个很好的问题。使用信号而不是集成到视图中是否有很多开销?如果是这样,我会修改代码。

标签: django django-signals


【解决方案1】:

根据您对 Django 新手的评论,我将提供一个替代解决方案。尝试在表单验证期间查找坏词。您可以按照以下格式通过writing a method for a specific field 检查特定的表单字段:def clean_<fieldname>。如果您的 CommentForm 具有字段名称 body,我们可以执行以下操作:

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

编辑:

看到你的观点后,还有一些额外的 cmets。

您应该能够将上面提到的def clean_body() 函数添加到您的CommentForm 并使其按预期运行。仅当 form.is_valid() 评估为 True 时,您发布的视图才会响应。如果某人的评论包含坏词并且form.is_valid 评估为False,您需要确保视图可以处理。请参阅示例代码here for a typical Django function based view。如果在修复这些问题后,您在发布CommentForm 和模板代码以及任何异常时仍然遇到问题。请务必删除您的原始信号代码。

p = Blog.objects.get(id=post_id) 替换为p = get_object_or_404(Blog, pk=post_id)。这样,如果用户提供了错误的post_id,他们将立即得到 404 而不是抛出异常,因为如果找不到单个对象,get() 会这样做。 get_object_or_404 here 上的文档。

您还可以通过在创建模型时使用automatically add the current time 来节省几行代码:

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

然后你可以从视图中删除c.created = timezone.now()

【讨论】:

  • 这看起来很清晰。最后一行应该是'return body'。此外,我想向用户打印一条消息,说明该评论包含坏词。我该如何添加这个?
  • 返回“用肥皂漱口”这一行给用户看,显然改成你喜欢的。发布您查看代码,我可以帮助您进一步了解如何使用上述代码。
  • 我已经用一些额外的信息更新了我的帖子。
【解决方案2】:

我认为你可以提出一些异常并捕获

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

在您的代码中:

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

raise ValidationError('this text explains an error')

【讨论】:

  • 您能详细说明一下这个 try/except 是如何集成到我的代码条件中的吗?
  • 这在调试模式下工作,谢谢。只是想知道这个异常在生产模式下会发生什么?
最近更新 更多