如何将我的 def clean_slug 函数包含到我的视图或模板中,以便它可以工作并显示“title alr exists”

Posted

技术标签:

【中文标题】如何将我的 def clean_slug 函数包含到我的视图或模板中,以便它可以工作并显示“title alr exists”【英文标题】:How do I include my def clean_slug function into my views or template so that it will work and show "title alr exist" 【发布时间】:2021-04-28 22:56:07 【问题描述】:

您好,我在表单中编写了一个def clean(self) 函数,以确保如果之前已经有相同标题的帖子,他们将返回一条消息,说明该标题已经存在,因此无法提交表单。

现在的问题:

当我输入一个已经存在的标题并尝试创建帖子时,之前输入的所有数据都将被删除,我将被重定向到一个新的表单。没有出现错误。我想要的是在我尝试单击创建按钮时向用户显示错误,以便所有数据都保留在那里,并且用户知道并且可以在再次尝试创建博客文章之前更改标题。

forms.py 中的return cleaned_data 也未定义...给出名称错误

指南:

注意!我的表单中没有 slug 字段。 slug 仅适用于每个单独的博客文章的 url。但基本上,蛞蝓由标题组成。例如,如果我的用户名是 hello 并且我的 Chief_title 是 bye,我的 slug 将是 hello-bye。正如您在模型中看到的那样,slug 和标题都必须是唯一的,但表单中没有 slug。

models.py

class BlogPost(models.Model):
 chief_title                    = models.CharField(max_length=50, null=False, blank=False, unique=True)
 brief_description = models.TextField(max_length=300, null=False, blank=False)
 author                     = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
 slug                   = models.SlugField(blank=True, unique=True)

views.py

def create_blog_view(request):
    context = 
    user = request.user
    if not user.is_authenticated:
        return redirect('must_authenticate')
    if request.method == 'POST':
        form = CreateBlogPostForm(request.POST or None, request.FILES or None)
    
        if form.is_valid():
            obj= form.save(commit = False)
            author = Account.objects.filter(email=user.email).first()
            obj.author = author
            obj.save()
            obj.members.add(request.user)
            context['success_message'] = "Updated"
            return redirect('HomeFeed:main')
        else:
            form = CreateBlogPostForm()
            context['form'] = form
    return render(request, "HomeFeed/create_blog.html", )

forms.py

class CreateBlogPostForm(forms.ModelForm):
    class Meta:
        model = BlogPost
        fields = ['chief_title']

    def clean(self):
        chief_title = self.cleaned_data['chief_title']
        qs = BlogPost.objects.filter(chief_title=chief_title)
        if qs.exists():
            raise forms.ValidationError('Post already exists')
        return cleaned_data

html

  <form class="create-form" method="post" enctype="multipart/form-data">% csrf_token %

    % if form.non_field_errors %
   form.non_field_errors  
    % endif %

   <!-- chief_title -->
   <div class="form-group">
    <label for="id_title">Chief Title!</label>
    <input class="form-control" type="text" name="chief_title" id="id_title" placeholder="Title" required autofocus>
   </div>   form.chief_title.errors



   <button class="submit-button btn btn-lg btn-primary btn-block" type="submit">CREATE</button>

  </form>   

【问题讨论】:

如果您刷新页面,显然数据会丢失。解决方法是将数据保存为会话,如果会话中存在对象,则将其用作初始数据。 使用表单视图。它将通过 form_invalid 方法自动处理。 您找到解决方案了吗?如果没有一个答案提供答案,您愿意分享吗? @raratiru 没用 :( 你不是Dutch,是吗? 【参考方案1】:

你可以创建一个自定义验证器来检查 slug 是否存在:

from django.core.exceptions import ValidationError

def validate_slug_exists(value):
    blog_post = BlogPost.objects.filter(slug=value)
    if blog_post.exists():
        raise ValidationError('The post with a given title already exists')

然后在您的 form 中将此 validator 添加到字段验证器列表中:

class CreateBlogPostForm(forms.ModelForm):
    chief_title = forms.CharField(validators = [validate_slug_exists])

更新

您也可以尝试在 form 类中使用validate_unique()

def validate_unique(self, exclude=None):
    qs = BlogPost.objects.all()

    if qs.filter(chief_title=self.chief_title).exists():
        raise ValidationError("Blog post with this title already exists")

【讨论】:

嗨兄弟,自定义验证器在views.py中是吗? 任何你想放的地方,我建议你把它放在你的forms.py文件里,这样你就不用导入它了 嘿兄弟遇到错误,我已经更新了问题让您查看错误 对,我错了,看看修改后的版本 嗯,试试 form.non_field_errors .【参考方案2】:

您可以引发 ValidationError,如 docs 所示。然后它将以用户的形式显示。

    def clean_slug(self):
        slug = slugify(self.cleaned_data.get("chief_title")) if len(self.cleaned_data.get("slug", )) == 0 \
            else self.cleaned_data.get("slug", )
        if BlogPost.objects.filter(slug=slug).exists():
            raise ValidationError(_('Slug already exists.'), code='invalid')
        return slug

【讨论】:

您好,我需要在views.py 和模板中添加任何内容吗?我已经用你的代码替换了我的代码,但基本上表单仍然无效并且没有引发错误 在我的表格中,只有一个 Chief_title 表格供他们填写,并且 Chief_title 将是 slug 字段的一部分。 clean_slug 函数写对了吗? 如何渲染整个表单?你不使用这种方法吗? docs.djangoproject.com/en/3.1/topics/forms/… 嘿兄弟,我已经更新了问题和问题中的代码,希望一切都更清楚。您可以检查一下,看看问题是否可以解决:) @dacx【参考方案3】:

如果你设置了unique = True,Django 会检查数据库中是否已经存在另一个条目,并在ModelForm.errors 中添加一个错误。

这发生在ModelForm.validate_unique

除非您想在错误中添加更多信息,例如现有对象的 url(它将花费 1 db hit),否则无需费心使用此方法。

否则,错误已经存在,您可以只返回带有错误的表单而不是返回表单的新实例,就像您目前在views.py 中所做的那样。

因此,this post 中解释的以下views.py 应该做你想做的事情:

app/views.py:

def create_blog_view(request):
    context = 
    # ...
    if request.method == 'POST':
        form = CreateBlogPostForm(request.POST or None, request.FILES or None)
        if form.is_valid():
            # do your thing
        else:
            context['form'] = form
    return render(request, "HomeFeed/create_blog.html", context)  # context instead of 

如果您想更高级并再次访问数据库,可以将现有对象的 url 添加到错误列表中,如下所示:

项目/settings.py

...
# If you want to provide more info
MY_UNIQUE_BLOGPOST_ERROR_MESSAGE = "This BlogPost already exists"
...

app/models.py

from django.db import models
from django.conf import settings
from django.urls import reverse


class BlogPost(models.Model):
    # ...
    slug = models.SlugField(
        blank=True, 
        unique=True, 
        error_messages="unique": settings.MY_UNIQUE_BLOGPOST_ERROR_MESSAGE),
    )

    def get_admin_url(self):
        return reverse("admin:app_blogpost_change", args=(self.id,))
    ...

app/forms.py

from django import forms
from django.conf import settings
from django.utils.html import format_html
from itertools import chain
from app.models import BlogPost

class CreateBlogPostForm(forms.ModelForm):
    class Meta:
        model = BlogPost
        fields = '__all__'

    def validate_unique(self):
        ''' 
            If unique error exists, find the relevant object and return its url.
            1 db hit
            There is no other need to override this method. 
        '''
        super().validate_unique()
        if settings.SHOP_ENTITY_UNIQUE_ERROR in chain.from_iterable(
            self.errors.values()
        ):
            instance = BlogPost.objects.get(slug=self.instance.slug)
            admin_url = instance.get_admin_url()
            instance_name = instance.__str__()

            self.add_error(
                None,
                forms.ValidationError(
                    format_html(
                        "This entry already exists: <a href=\"0\">1</a>",
                        admin_url,
                        instance_name,
                    ),
                    code="unique",
                ),
            )

【讨论】:

以上是关于如何将我的 def clean_slug 函数包含到我的视图或模板中,以便它可以工作并显示“title alr exists”的主要内容,如果未能解决你的问题,请参考以下文章

如何编辑我的入队脚本函数以包含 Internet Explorer 和页面模板样式表?

如何将Match对象包含到ReactJs组件类中?

如何将我的应用程序作为模块包含在 Swift Playground 中?

如果它们位于单独的命名空间中,我如何将我的规范用于其预期目的?

如何在不包含节点模块文件夹的情况下将我的 React 项目上传到 GitHub [重复]

如何将我的 main() 函数输出为 CSV 文件