Django Form 组件用于对页面进行初始化,生成 HTML 标签,此外还可以对用户提交的数据进行校验(显示错误信息)。
报错信息显示顺序:
- 先显示字段属性中的错误信息,然后再显示局部钩子的错误信息。
- 若显示了字段属性的错误信息,就不会显示局部钩子的错误信息。
- 若有全局钩子,则全局钩子是等所有的数据都校验完,才开始进行校验,并且全局钩子的错误信息一定会显示。
那么什么是钩子呢
钩子就是自定义的错误规则,局部钩子命名用clean_xx(xx为字段名),全局钩子则不需要加上字段名。
使用 Form 组件,需要先导入 forms:
from django import forms
首先在app下添加一个自定义的钩子文件my_froms.py功能为对前面的数据库内容实现增加记录操作,不过利用钩子对添加的信息进行校验,如果发生错误则抛出错误。代码如下:
from django import forms
from django.core.exceptions import ValidationError
from dbh.models import Hook#引入模型
class EmpForm(forms.Form):
title = forms.CharField(min_length=4, label="书籍名字", error_messages={"min_length": "你太短了", "required": "该字段不能为空!"})
price = forms.IntegerField(label="价格")
r_price = forms.IntegerField(label="再次输入价格")
publish = forms.CharField(label="出版社")
pub_date = forms.DateTimeField(label = "出版日期")
def clean_title(self): # 局部钩子
val = self.cleaned_data.get("title")
if val.isalpha():
raise ValidationError("书籍名用汉字表示")
elif Hook.objects.filter(title=val):
raise ValidationError("该书籍已存在!")
else:
return val
def clean(self): # 全局钩子 确认两次输入的价格是否一致。
val = self.cleaned_data.get("price")
r_val = self.cleaned_data.get("r_price")
if val and r_val:
if val == r_val:
return self.cleaned_data
else:
raise ValidationError("请确认工资是否一致。")
else:
return self.cleaned_data
字段属性:
- label:输入框前面的文本信息。
- error_message:自定义显示的错误信息,属性值是字典, 其中 required 为设置不能为空时显示的错误信息的 key。
然后在视图里定义函数,使之能够获获取到前端响应得到的错误信息
def add_emp(request):
if request.method == "GET":
form = EmpForm()
return render(request, "add_emp.html", {"form": form})
else:
form = EmpForm(request.POST)
if form.is_valid(): # 进行数据校验
# 校验成功
data = form.cleaned_data # 校验成功的值,会放在cleaned_data里。
data.pop("r_price")
print(data)
Hook.objects.create(**data)
return HttpResponse(
'ok'
)
return redirect("/index/")
else:#校验失败
print(form.errors) # 打印错误信息
clean_errors = form.errors.get("__all__")#获取全局钩子错误信息
#print(222, clean_errors)
return render(request, "add_emp.html", {"form": form, "clean_errors": clean_errors})
并在url里绑定函数,这里同之前一样不在累述。
写好这三项后,就开始自定义自己的前端文件了
在事务文件夹中新建add_emp.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h3>添加书籍</h3>
<!--<form action="" method="post" novalidate>-->
<!-- {% csrf_token %}-->
<!-- <p>书籍名称:<input type="text" name="title"></p>-->
<!-- <span>{{ form.title.errors.0 }}</span>-->
<!-- <p>价格:<input type="text" name="price"></p>-->
<!-- <span>{{ form.price.errors.0 }}{{ clear_errors.0 }}</span>-->
<!-- <p>再次输入价格:<input type="text" name="r_price"></p>-->
<!-- <span>{{ form.r_price.errors.0 }}{{ clear_errors.0 }}</span>-->
<!-- <p>出版社:<input type="text" name="publish"></p>-->
<!-- <span>{{ form.publish.errors.0 }}</span>-->
<!-- <p>出版日期:<input type ="text" name="pub_data"></p>-->
<!-- <span>{{ form.pub_date.errors.0 }}</span>-->
<!-- <input type="submit">-->
<!--</form>-->
<!--2、通过form对象的as_p方法实现#-->
<!--<form action="" method="post" novalidate>-->
<!-- {% csrf_token %}-->
<!-- {{ form.as_p }}-->
<!-- <input type="submit">-->
<!--</form>-->
<!--3、手动获取form对象的字段#-->
<form action="" method="post" novalidate>
{% csrf_token %}
<div>
<label for="id_{{ form.title.title }}">书籍名称</label>
{{ form.title }} <span>{{ form.title.errors.0 }}</span>
</div>
<div>
<label for="id_{{ form.price.price }}">价格</label>
{{ form.price }} <span>{{ form.price.errors.0 }}</span>
</div>
<div>
<label for="id_{{ form.r_price.r_price }}">再次输入价格</label>
<span> {{form.r_price}} {{ form.r_price.errors.0 }}{{ clean_errors.0 }}</span>
</div>
<div>
<label for="id_publish">出版社</label>
{{ form.publish }} <span>{{ form.publish.errors.0 }}</span>
</div>
<div>
<label for="id_pub_data">出版日期</label>
{{ form.pub_date }} <span>{{ form.pub_date.errors.0 }}</span>
</div>
<input type="submit">
</form>
<!--{#4、用for循环展示所有字段#}-->
<!--<form action="" method="post" novalidate>-->
<!-- {% csrf_token %}-->
<!-- {% for field in form %}-->
<!-- <div>-->
<!-- <label for="id_{{ field.name }}">{{ field.label }}</label>-->
<!-- {{ field }} <span>{{ field.errors.0 }}</span>-->
<!-- </div>-->
<!-- {% endfor %}-->
<!-- <input type="submit">-->
<!--</form>-->
</body>
</html>
写了四种在前段实现的方法,均测试均能正确的抛出错误。
先写到这里吧