如何在 Django 中修改 Bootstrap 4 表单验证信息呈现方式?
Posted
技术标签:
【中文标题】如何在 Django 中修改 Bootstrap 4 表单验证信息呈现方式?【英文标题】:How to modify Bootstrap 4 form validation information presentation in Django? 【发布时间】:2021-03-11 05:08:08 【问题描述】:我正在使用 Django 和 Bootstrap 4。我想自定义表单验证信息在我正在使用的模板中的显示方式。当当前模板发生错误时,无效的输入元素有红色轮廓,错误消息显示为弹出窗口。另外,正确输入的输入元素没有绿色轮廓,它们只是没有轮廓。
我想做以下事情:
发生错误时在字段下方显示错误消息 为输入正确的字段添加绿色轮廓我尝试了多种解决方案,包括:
this tutorial this GitHub gist the Stack Overflow answers from this question我的情况没有任何效果。
我当前的代码:
submit_job_listing.html
(模板):
% extends "base.html" %
% block title % Submit a job % endblock %
% block nav_item_post_a_job %active% endblock nav_item_post_a_job %
% block head %
job_listing_form.media.css
% endblock %
% block content %
<h1>Submit a job listing</h1>
<div class="container">
<form method="post" enctype="multipart/form-data">
% csrf_token %
<div class="row text-center">
<h2> <b>Job listing information</b> </h2>
</div>
<br/>
% for field in job_listing_form.visible_fields %
<div class="form-group">
<div class="row">
<p> field.label_tag </p>
</div>
<div class="row">
% if field.help_text %
<p class="form-text text-muted"> field.help_text </p>
% endif %
</div>
<div class="row">
field
</div>
</div>
% endfor %
<br/>
<div class="row text-center">
<h2> <b>Employer information</b> </h2>
</div>
<br/>
% for field in employer_form.visible_fields %
<div class="form-group">
<div class="row">
<p> field.label_tag </p>
</div>
<div class="row">
% if field.help_text %
<p class="form-text text-muted"> field.help_text </p>
% endif %
</div>
<div class="row">
field
</div>
</div>
% endfor %
<input type="submit" value="Submit" class="btn btn-primary" />
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
job_listing_form.media.js
</div>
% endblock %
views.py
(相关部分):
def submitJobListing(request):
if request.method == "POST":
employer_form = EmployerForm(request.POST, request.FILES)
job_listing_form = JobListingForm(request.POST, request.FILES)
#check if employer with that name already exists
employer_name = str(request.POST.get("name", ""))
try:
employer_with_the_same_name = Employer.objects.get(name=employer_name)
except ObjectDoesNotExist:
employer_with_the_same_name = None
employer = None
if (employer_with_the_same_name != None):
employer = employer_with_the_same_name
if employer == None and employer_form.is_valid() and job_listing_form.is_valid():
employer = employer_form.save()
job_listing = job_listing_form.save(commit=False)
job_listing.employer = employer
job_listing.save()
job_listing_form.save_m2m()
return SimpleTemplateResponse("employers/successful_job_listing_submission.html")
else:
employer_form = EmployerForm()
job_listing_form = JobListingForm()
context =
"employer_form": employer_form,
"job_listing_form": job_listing_form,
return render(request, 'employers/submit_job_listing.html', context)
forms.py
(相关部分):
class EmployerForm(forms.ModelForm):
name = forms.CharField(max_length=100)
#location = forms.CharField(widget=LocationWidget)
short_bio = forms.CharField(widget=forms.Textarea)
website = forms.URLField()
profile_picture = forms.ImageField()
def __init__(self, *args, **kwargs):
super(EmployerForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
if isinstance(visible.field.widget, (forms.widgets.TextInput, forms.widgets.Textarea, forms.widgets.URLInput, LocationWidget)):
visible.field.widget.attrs['class'] = 'form-control'
if isinstance(visible.field.widget, forms.widgets.ClearableFileInput):
visible.field.widget.attrs['class'] = 'form-control-file'
class Meta:
model = Employer
fields = ["name", "short_bio", "website", "profile_picture"]
class JobListingForm(forms.ModelForm):
job_title = forms.CharField(max_length=100, help_text="What's the job title?")
job_description = forms.CharField(widget=forms.Textarea)
job_requirements = forms.CharField(widget=forms.Textarea)
what_we_offer = forms.CharField(widget=forms.Textarea)
location = forms.CharField(widget=LocationWidget)
remote = forms.BooleanField()
job_application_url = forms.URLField()
point_of_contact = forms.EmailField()
categories = forms.ModelMultipleChoiceField(
queryset=Category.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=True)
def __init__(self, *args, **kwargs):
super(JobListingForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
if isinstance(visible.field.widget, (forms.widgets.TextInput, forms.widgets.Textarea, forms.widgets.URLInput, forms.widgets.EmailInput, LocationWidget)):
visible.field.widget.attrs['class'] = 'form-control'
if isinstance(visible.field.widget, (forms.widgets.CheckboxInput, forms.widgets.CheckboxSelectMultiple)):
visible.field.widget.attrs['class'] = 'form-check'
class Meta:
model = JobListing
fields = ["job_title", "job_description", "job_requirements", "what_we_offer", "location", "remote", "job_application_url", "categories", "point_of_contact"]
谁能告诉我怎样才能达到我想要的效果?
更新 1:
我尝试添加检查field.errors
的代码,但它不起作用。
这是submit_job_listing.html
模板文件:
% extends "base.html" %
% load widget_tweaks %
% block title % Submit a job % endblock %
% comment % https://***.com/questions/50028673/changing-active-class-in-bootstrap-navbar-not-staying-in-inherited-django-templa % endcomment %
% block nav_item_post_a_job %active% endblock nav_item_post_a_job %
% block head %
job_listing_form.media.css
<!---
<style>
input, select width: 100%
</style>
--->
% endblock %
% block content %
% comment %
https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html
% endcomment %
<h1>Submit a job listing</h1>
<div class="container">
<form method="post" enctype="multipart/form-data">
% csrf_token %
<div class="row text-center">
<h2> <b>Job listing information</b> </h2>
</div>
<br />
<div class="row text-center">
<p> <b>Note: Fields marked with an asterisk (*) are required</b> </p>
</div>
<br/>
% for field in job_listing_form.visible_fields %
<div class="form-group">
<div class="row">
<p> field.label_tag field.field.required|yesno:"*," </p>
</div>
<div class="row">
% if field.help_text %
<p class="form-text text-muted"> field.help_text </p>
% endif %
</div>
<div class="row">
field
<p> field.errors </p>
% if field.errors %
<div class="border-bottom-danger">
field.errors
</div>
% endif %
</div>
</div>
% endfor %
<br/>
<div class="row text-center">
<h2> <b>Employer information</b> </h2>
</div>
<br />
<div class="row text-center">
<p> <b>Note: Fields marked with an asterisk (*) are required</b> </p>
</div>
<br/>
% for field in employer_form.visible_fields %
<div class="form-group">
<div class="row">
<p> field.label_tag field.field.required|yesno:"*," </p>
</div>
<div class="row">
% if field.help_text %
<p class="form-text text-muted"> field.help_text </p>
% endif %
</div>
<div class="row">
field
</div>
</div>
% endfor %
<input type="submit" value="Submit" class="btn btn-primary" />
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
job_listing_form.media.js
</div>
% endblock %
当我只单击提交按钮而不输入任何内容时,所有输入都有一个红色轮廓,但没有任何内容打印为field.errors
。我不知道为什么会这样。 为什么会这样?
【问题讨论】:
【参考方案1】:% load widget_tweaks %
<div class="col-12 col-md-6">
<div class="form-group">
<label for=" form.field1.id_for_label " class="text-capitalize"> form.field1.label|title % if form.field1.field.required %<span class="text-danger ml-1">*</span>% endif %</label>
% if form.is_bound %
% if form.field1.errors %
% render_field form.name class="form-control is-invalid" %
% for error in form.field1.errors %
<div class="invalid-feedback">
error
</div>
% endfor %
% else %
% render_field form.field1 class="form-control is-valid" %
% endif %
% else %
% render_field form.field1 class="form-control" %
% endif %
% if form.field1.help_text %
<small class="form-text text-muted"> form.field1.help_text </small>
% endif %
</div>
</div>
</div>
【讨论】:
在您的代码中,您正在循环访问我提到的所有字段,以保留每个字段手册。因此,在您的情况下,您必须将 field1 替换为您拥有的正确字段【参考方案2】:你试过在模板中调试吗?
我做了你想要实现的事情:
<form method="post"> % csrf_token %
% for field in form %
<div class="form-group">
field
<label class="control-label" for=" field.id_for_label "> field.label </label>
% if field.errors %
<div class="border-bottom-danger">
field.errors
</div>
% endif %
</div>
% endfor %
<button class="btn btn-block" type="submit">Submit</button>
</form>
地点:
field
是输入,您在其中正确添加 visible.field.widget.attrs['class'] = 'form-control'
然后,您想要(我猜)的错误存储在该字段中,因此如果有的话,您可以使用 field.errors
获取它。
你的代码和我的不同之处在于我使用的是field.errors
而不是if field.help_text
,希望对你有帮助。
我建议您在模板中放置断点,然后分析您的form
对象。然后你可以在你的前端做任何你想做的事情。
-
如果没有错误: 将类 outline-green 添加到您的输入包装器(
<div class="row"
)
如果出现错误:在输入下方的 div 中显示错误
PS : 如果你想概述输入,而不是行包装,你可以通过 css 来完成(或者如果你正在使用它,最好使用 Sass):
.row.outline-green > input
border: 1px solid green;
<div class="row outline-green">
field
</div>
【讨论】:
对此我有两个问题:1) 如何在模板中放置断点?我正在使用 Atom 和终端 - 我需要为此使用其他东西吗? 2) 我更新了我的问题 -field.errors
似乎是空的。你能解释一下为什么会这样吗?
1) Check on this thread。就个人而言,我正在使用 pycharm pro。 2)你真的得到 field.help_text
的错误吗?尝试放置一些断点,以查看job_listing_form
和employer_form
是如何填充的。如果您不能在模板中,请在返回上下文之前尝试在视图中。使用断点进行调试将为您节省大量时间。
当前模板将None
打印为field.errors
。我不是通过 PyCharm 设置断点(因为我只有社区版),而是通过您提供的链接中的第二个答案。断点仅在第一次渲染模板时被激活。如果我单击提交按钮,则不会再次触发断点。这对我来说很奇怪 - 我认为 Django 会在每个 POST 请求上重新呈现模板,即使它是无效的?也许这个错误与我的观点有关?
删除条件% if field.errors %
之前的<p> field.errors </p>
。然后检查您的job_listing_form.visible_fields
是如何填充断点的。是否有任何变量带有您所期望的任何类型的错误。 PS:如果您需要在模板中进行深度调试(逐步),请试用 pycharm pro 及其试用版 30 天(还有学生版 1 年)。
field.errors
为空,因为消息“请填写此字段”。由网络浏览器呈现。即使我填写了其他输入字段并单击提交按钮,它实际上并没有向服务器发送 POST 请求,但浏览器只是呈现“请填写此字段”。再次。如何解决此浏览器功能,以便测试我的错误报告功能?以上是关于如何在 Django 中修改 Bootstrap 4 表单验证信息呈现方式?的主要内容,如果未能解决你的问题,请参考以下文章
django-bootstrap4|django 加载popper.min.js失败
python测试开发django-120.bootstrap-table表格添加操作按钮(查看/修改/删除)
如何在 Django 应用程序中使用 bootstrap-datepicker?
python测试开发django-126.bootstrap-table表格内操作按钮(修改/删除) 功能实现