Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在Django中使用验证器工作不正常_Python_Django - Fatal编程技术网

Python 在Django中使用验证器工作不正常

Python 在Django中使用验证器工作不正常,python,django,Python,Django,我最近学习了验证器以及它们是如何工作的,但我正在尝试向我的博客项目添加一个函数,以便在使用坏词时引发错误。 我有一个txt中的坏单词列表,并将代码添加到models.py中。问题是,由于某种原因,没有任何东西被阻止,我不确定 这是模型 class Post(models.Model): title = models.CharField(max_length=100, unique=True) ---------------other unrelated--------

我最近学习了验证器以及它们是如何工作的,但我正在尝试向我的博客项目添加一个函数,以便在使用坏词时引发错误。 我有一个txt中的坏单词列表,并将代码添加到models.py中。问题是,由于某种原因,没有任何东西被阻止,我不确定

这是模型

class Post(models.Model):
       title = models.CharField(max_length=100, unique=True)
       ---------------other unrelated------------------------

def validate_comment_text(text):
    with open("badwords.txt") as f:
        censored_word = f.readlines()
    words = set(re.sub("[^\w]", " ", text).split())
    if any(censored_word in words for censored_word in CENSORED_WORDS):
        raise ValidationError(f"{censored_word} is censored!")

class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    content = models.TextField(max_length=300, validators=[validate_comment_text])
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now=True)
from django.db import models


class Model1(models.Model):

    def clean(self):
        print("Inside Model1.clean()")

    def save(self, *args, **kwargs):
        print('Enter Model1.save() ...')
        super().save(*args, **kwargs)
        print('Leave Model1.save() ...')
        return

class Model2(models.Model):

    def clean(self):
        print("Inside Model2.clean()")

    def save(self, *args, **kwargs):
        print('Enter Model2.save() ...')
        self.full_clean()
        super().save(*args, **kwargs)
        print('Leave Model2.save() ...')
        return
以下是views.py:

class PostDetailView(DetailView):
    model = Post
    template_name = "blog/post_detail.html"  # <app>/<model>_<viewtype>.html

    def get_context_data(self, *args, **kwargs):
        context = super(PostDetailView, self).get_context_data()
        post = get_object_or_404(Post, slug=self.kwargs['slug'])
        comments = Comment.objects.filter(
            post=post).order_by('-id')
        total_likes = post.total_likes()
        liked = False
        if post.likes.filter(id=self.request.user.id).exists():
            liked = True

        if self.request.method == 'POST':
            comment_form = CommentForm(self.request.POST or None)
            if comment_form.is_valid():
                content = self.request.POST.get('content')
                comment_qs = None

                comment = Comment.objects.create(
                    post=post, user=self.request.user, content=content)
                comment.save()
                return HttpResponseRedirect("blog/post_detail.html")
        else:
            comment_form = CommentForm()

        context["comments"] = comments
        context["comment_form"] = comment_form
        context["total_likes"] = total_likes
        context["liked"] = liked
        return context

    def get(self, request, *args, **kwargs):
        res = super().get(request, *args, **kwargs)
        self.object.incrementViewCount()
        if self.request.is_ajax():
            context = self.get_context_data(self, *args, **kwargs)
            html = render_to_string('blog/comments.html', context, request=self.request)
            return JsonResponse({'form': html})
        return res

class PostCommentCreateView(LoginRequiredMixin, CreateView):
    model = Comment
    form_class = CommentForm

    def form_valid(self, form):
        post = get_object_or_404(Post, slug=self.kwargs['slug'])
        form.instance.user = self.request.user
        form.instance.post = post
        return super().form_valid(form)

我是新学员,如果您能对答案提供一些解释,我将不胜感激,这样我就可以避免重复同样的错误。

验证程序仅在您使用
ModelForm
时运行。如果直接调用
comment.save()
,验证程序将不会运行

因此,您需要使用
ModelForm
验证字段,或者可以添加
pre\u save
信号并在那里运行验证(您需要手动调用该方法,或者使用
full\u clean
运行验证)。 比如:

from django.db.models.signals import pre_save

def validate_model(sender, instance, **kwargs):
    instance.full_clean()

pre_save.connect(validate_model, dispatch_uid='validate_models')

我相信有很多方法可以解决这个问题,但我最终决定在我所有的Django项目中采用一种常见的做法:

当模型需要验证时,我重写clean()以在一个地方收集所有验证逻辑,并提供适当的错误消息

在clean()中,可以访问所有模型字段,不需要返回任何内容;只需根据需要提出ValidationErrors:

from django.db import models
from django.core.exceptions import ValidationError


class MyModel(models.Model):

    def clean(self):
         
        if (...something is wrong in "self.field1" ...) {
            raise ValidationError({'field1': "Please check field1"})
        }
        if (...something is wrong in "self.field2" ...) {
            raise ValidationError({'field2': "Please check field2"})
        }

        if (... something is globally wrong in the model ...) {
            raise ValidationError('Error message here')
        }
管理员已经从中获益,从ModelAdmin.save_model()调用clean(), 以及在变更视图中显示任何错误;当ValidationError对字段进行寻址时, 表格中将强调相应的小部件

要在以编程方式保存模型时运行相同的验证,只需按如下所示重写save():

class MyModel(models.Model):

    def save(self, *args, **kwargs):
        self.full_clean()
        ...
        return super().save(*args, **kwargs)
证明:

文件models.py

class Post(models.Model):
       title = models.CharField(max_length=100, unique=True)
       ---------------other unrelated------------------------

def validate_comment_text(text):
    with open("badwords.txt") as f:
        censored_word = f.readlines()
    words = set(re.sub("[^\w]", " ", text).split())
    if any(censored_word in words for censored_word in CENSORED_WORDS):
        raise ValidationError(f"{censored_word} is censored!")

class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    content = models.TextField(max_length=300, validators=[validate_comment_text])
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now=True)
from django.db import models


class Model1(models.Model):

    def clean(self):
        print("Inside Model1.clean()")

    def save(self, *args, **kwargs):
        print('Enter Model1.save() ...')
        super().save(*args, **kwargs)
        print('Leave Model1.save() ...')
        return

class Model2(models.Model):

    def clean(self):
        print("Inside Model2.clean()")

    def save(self, *args, **kwargs):
        print('Enter Model2.save() ...')
        self.full_clean()
        super().save(*args, **kwargs)
        print('Leave Model2.save() ...')
        return
文件test.py

from django.test import TestCase
from project.models import Model1
from project.models import Model2

class SillyTestCase(TestCase):

    def test_save_model1(self):
        model1 = Model1()
        model1.save()

    def test_save_model2(self):
        model2 = Model2()
        model2.save()
结果:

❯ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
Enter Model1.save() ...
Leave Model1.save() ...
.Enter Model2.save() ...
Inside Model2.clean()
Leave Model2.save() ...
.
----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK
Destroying test database for alias 'default'...

(1) 你的缩进消失了。我假设这只是一个复制/粘贴问题。(2) 此检查区分大小写-如果您将单词存储为全部大写/小写或其他形式,则很有可能许多单词不匹配。建议将文本转换为所有小写字母,并将所有小写字母存储在
删失的单词中,看看这是否有帮助。@michjnich这只是一个复制/粘贴错误导致缩进错误,但这不是无法工作的问题不清楚为什么会被否决?问题中没有足够的信息来判断它是否是实际的解决方案,但似乎是一个合理的建议!我同意:这个答案是有用的,所以我会投赞成票;)出于个人喜好,我宁愿重写save(),因为这对我来说更为明确。当您需要在另一个文件中声明模型的挂钩时,信号更合适ap@AmanGarg我一直在尝试pre_save,但我没有成功实现它,我已经用我的试用版更新了帖子。@michjnich我已经加入了帖子模型和视图,以便为问题添加更多细节。Thanks@Shiko
validate\u comment\u文本(发件人、文本、实例、**kwargs)
没有正确的签名。第二个参数是
实例
,因此只需更新答案中提到的签名即可。您可以将
self.instance.full_clean()
添加到
def clean(self)
中以运行模型验证。如果有问题,它会像其他问题一样引发一个
验证错误。。。切换到ModelForm也很好,模型验证将自动进行,并设置字段。@TimTisdall。。。既然你说了“并在models.py中添加了代码”,我就是这么做的。我相信这有一个很好的理由:如果您以编程方式保存模型,那将享受同样的验证。只要模型的代码保护自身,您的数据将始终处于良好状态,不管用户界面(即模型表单)的行为好坏@TimTisdall“您可以将self.instance.full_clean()添加到def clean(self)”中。。。我相信Django的工作方向正好相反:首先在Model.save()中调用full_clean(),然后(因此)框架将调用clean()。我同意这里的方法名称相当混乱;)@TimTisdall我真的不明白验证错误是表单的概念从何而来。DRF也在序列化程序和模型中使用它们,下面列出了ValidationError的具体用法、调用顺序以及除了单个字段清理方法之外还需要clean()的原因。