如何将我的 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 和页面模板样式表?
如何将我的应用程序作为模块包含在 Swift Playground 中?
如果它们位于单独的命名空间中,我如何将我的规范用于其预期目的?