我在之前做了一个关于AJAX和form组件的笔记,可以参考:Django学习笔记(8)——前后台数据交互实战(AJAX)Django学习笔记(6)——Form表单

  我觉得自己在写Django笔记(8)的时候,我只是对AJAX有个粗略的了解,就明白其两大优点,局部刷新和异步交互。Form组件知识虽然大多数都明白了,但是对局部钩子和全局钩子还不是很清楚。留了个坑,所以在以后的学习中,肯定会再遇到。

  现在,我感觉自己将关于AJAX和Django的数据交互这部分了解清楚了,而且将Form组件的钩子也理解透彻了。特意做个笔记记录自己的学习过程。也是在Django笔记(8)的时候说过的,我将这段内容理清楚了,会写一个易于理解的文章巩固,而这篇文件就是。

  下面我分别将自己所做的AJAX知识笔记,Form组件中局部钩子和全局钩子的笔记展示一下。其中局部钩子和全局钩子都做了源码分析,是为了更好的理解其原理吧。

AJAX知识

1,AJAX请求头中常见contentType

  数据发送出去,还需要服务端解析成功才有意义。Python内置了自动解析常见数据格式的功能。服务端通常是根据请求头(headers)中的Content-Type 字段获取请求头中的消息主体是用何种方式编码,再对主体进行解析。所以说到POST提交数据方案,包含了Content-Type 和消息主体编码方式两部分。

  下面我们一起来看看ajax中POST请求的Content-Type。以application开头的媒体格式类型:

application/xhtml+xml :XHTML格式

application/xml     : XML数据格式

application/atom+xml  :Atom XML聚合格式   

application/json    : JSON数据格式

application/pdf       :pdf格式 

application/msword  : Word文档格式

application/octet-stream : 二进制流数据(如常见的文件下载)

application/x-www-form-urlencoded :
<form encType=””>中默认的encType,form表单数据被编码为key/value格式
发送到服务器(表单默认的提交数据的格式)

  ContentType指的是请求体的编码类型,常见的有三种:

1.1,application/x-www-form-urlencoded

  这应该是最常见的POST提交数据的方式了。浏览器的原生表单<form>默认的提交方式,如果不设置enctype属性,那么最终就会以application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样(无关的请求头在本文中都省略掉了):

POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8 user=james&age=24

  

  下面将参数的默认使用方法总结如下:

data:        当前ajax请求要携带的数据,是一个object对象,ajax方法就会默认地把
它编码成某种格式(urlencoded:?a=1&b=2)发送给服务端;此外,ajax默认以get方
式发送请求。 contentType:"application/x-www-form-urlencoded"。发送信息至服务器时内容
编码类型。用来指明当前请求的数据编码格式;urlencoded:?a=1&b=2;

  

1.2,multipart/form-data

  这又是一个常见的POST数据提交的方式。我们使用表单上传文件时,必须让表单的enctype 等于 multipart/form-data。

  直接看一个例子:

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA ------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="user" james
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

  这个例子稍微复杂点,首先生成了一个boundary 用于分割不同的字段,为了避免与正文内容重复,boundary很长很复杂。然后Content-Type里指明了数据是以 multipart/form-data 来编码。

  本次请求的 boundary 是什么内容?

  消息主体里是按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始。紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或者二进制)。如果传输的是文件,还要包含文本名和文件类型信息。消息主体最后以 --boundary-- 标识结束。关于 multipart/form-data 的详细定义,请前往 rfc 1967 查看。

  这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

  上面提到的这两种POST数据的方式,都是浏览器原生支持的,而且现阶段标准中原生表单也只支持这两种方式。其实enctype 还支持 text/plain,不过用的非常少。

  随着越来越多的Web站点,尤其是WebAPP,全部使用AJAX进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。

1.3,application/json

  application/json 这个Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人吧他作为请求头,用来告诉服务端消息主体是序列化的JSON字符串。由于JSON规范的流行,处理低版本IE之外的各大浏览器都支持原生的JSON.stringify,服务端语言也有处理JSON的函数,使用JSON不会遇到什么麻烦。

  上述这种默认参数形式,data中的csrf跨站请求伪造键值对会被中间件自动识别,ContentType参数还有如下一种形式,介绍如下:

contentType:"application/json",即向服务器发送一个json字符串。

注意:contentType:"application/json"一旦设定,data必须是json字符串,不能是json对象

  这种类型,使用request.POST 无法显示,这种类型要使用 request.body才能显示数据。

1.4,text/xml(不常用)

  相比于JSON,XML不能更好的适用于数据交换,它包含了太多的包装,而且它跟大多数编程语言的数据模型不匹配,让大多数程序员感到诧异,XML是面向数据的,JSON是面向对象和结构的,后者会给程序员一种更加亲切的感觉。

  我们现在一般这样来使用:

  • 1,XML存储数据,存储配置文件等需要结构化存储的地方使用;
  • 2,数据传输,数据交互使用JSON

  下面就是 ajax Content-Type 为 text/xml 的请求:

2,文件上传

  注意:我们使用表单上传文件时,必须让表单的enctype 等于 multipart/form-data。

2.1  基于form表单的文件上传

  html代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>upload</title>
</head>
<body> {# 文件上传的form#}
{#<form method="post" enctype="multipart/form-data">#}
<form method="post" action="/user8_book/upload.html/" enctype="multipart/form-data">
{% csrf_token %}
<p><input id="name" type="text" name="input-name" placeholder="请输入文件名称" ></p>
<p><input id="file" type="file" name="file"></p>
<p><input id="submit" type="submit" value="submit"></p>
</form> </body>
</html>

  view视图函数:

from django.shortcuts import render, HttpResponse
import os # Create your views here. def index(request):
if request.method == 'POST':
obj = request.FILES.get('file')
print("获取文件的名称: ", obj.name) f = open(os.path.join('statics/upload', obj.name), 'wb')
for line in obj.chunks():
f.write(line)
f.close() # POST请求数据
print("POST 请求数据: ", request.POST)
# GET 请求数据
print("上传的文件数据: ", request.FILES) return HttpResponse("upload OK") return render(request, 'file_put/index.html')

  我们上传数据后,在后台终端可以看到下面信息:

获取文件的名称:  distance.jpg

POST 请求数据:  <QueryDict: {'csrfmiddlewaretoken':
['uHoRIy1DrQyS2nD87UndwfoQXH9KEd5zEcIpzjZPjo2zk84TfBatR9QCbaAmckFh'],
'user': ['file1']}> 上传的文件数据: <MultiValueDict: {'avatar': [<InMemoryUploadedFile: distance.jpg
(image/jpeg)>]}>

  

2.2 基于AJAX文件上传

  html代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title> <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js"></script> </head>
<body> <h2>基于AJAX文件上传</h2>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>username:<input type="text" name="user" placeholder="请输入文件名称"></p>
<p>photo:<input type="file" name="avatar" ></p>
<p><input type="submit" value="ajax submit" class="btn"></p>
</form>
</body> <script>
// ajax上传
$('.btn').click(function () {
var formdata = new FormData();
formdata.append('user', $("#user").val());
formdata.append('avatar', $("#avatar")[0].files[0]); $.ajax({
url: '',
type: 'post',
contentType: false,
processData: false,
data: formdata,
success: function (data){
console.log(data)
}
})
})
</script>
</html>

  注意1:使用ajax上传文件的时候,前端代码必须出现下面:

            contentType: false,
processData: false,

  注意2:AJAX(Formdata)是什么呢?

  XMLHttpRequest Level 2 添加了一个新的接口 FormData,利用FormData对象,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest 的 send()  方法来异步的提交这个“表单”。比起普通的 ajax,使用FormData的最大优点就是我们可以异步上传一个二进制文件。

  所有主流浏览器的较新版本都已经支持这个对象了。比如Chtome 7+, Firefox 4+, IE 10+,Opera 12+,Safari 5+ 等。

  view函数:

from django.shortcuts import render, HttpResponse
import os # Create your views here. def index(request):
if request.method == 'POST':
obj = request.FILES.get('avatar')
print("获取文件的名称: ", obj.name) f = open(os.path.join('statics/upload', obj.name), 'wb')
for line in obj.chunks():
f.write(line)
f.close() # POST请求数据
print("POST 请求数据: ", request.POST)
# GET 请求数据
print("上传的文件数据: ", request.FILES) return HttpResponse("upload OK") return render(request, 'file_put/index.html') def ajax_put(request):
if request.method == 'POST':
obj = request.FILES.get('avatar')
print("获取文件的名称: ", obj)
# POST请求数据
print("POST 请求数据: ", request.POST)
# 文件的请求数据
print("上传的文件数据: ", request.FILES)
f = open(os.path.join('statics/upload', obj.name), 'wb')
for line in obj.chunks():
f.write(line)
f.close() return HttpResponse("upload OK") # if request.method == 'POST':
# # 请求报文中的请求体
# print(request.body)
# print(request.POST)
# print(request.FILES)
# file_obj = request.FILES.get('avatar')
# with open(file_obj.name, 'wb') as f:
# for line in file_obj:
# f.write(line)
# return HttpResponse("AJAX OK") return render(request, 'file_put/ajax_index.html')

  我们上传数据后,在后台终端可以看到下面信息:

获取文件的名称:  50788990.jpg

POST 请求数据:  <QueryDict: {'csrfmiddlewaretoken':
['x1KicPbnZ6k7lg7AeerN4WBfUC14JLeoHw4Q3A9zREOOD1ylmVe3pQ3185sGhSO6'],
'user': ['file132']}> 上传的文件数据:
<MultiValueDict: {'avatar': [<InMemoryUploadedFile: 50788990.jpg (image/jpeg)>]}>

  

Form组件学习

1,什么是forms组件

  forms组件就是一个类,可以检查前端传来的数据,是否合法。

  例如前端传来的邮箱数据,判断邮箱格式是否正确,用户名不能以什么开头等等。

2,form组件的使用语法

  简单举个例子说一下:

from django.shortcuts import render, HttpResponse
from django import forms # 1.先写一个类,继承Form
class MyForm(forms.Form):
# 定义一个属性,可以用来校验字符串类型
# 限制最大长度是8,最小长度是3
name=forms.CharField(max_length=8,min_length=3)
pwd=forms.CharField(max_length=8,min_length=3,required=True)
# 校验是否是邮箱格式
email=forms.EmailField() # 2.在视图函数中使用MyForm来校验数据
# 实例化产生对象,传入要校验的数据(可以传字典字典,也可以不传)
myform=MyForm(request.POST) # 3.校验,is_valid如果是true表示校验成功(满足myform里的条件),反之,校验失败
if myform.is_valid():
# myform.clean_data 表示校验通过的数据
print(myform.cleaned_data)
return HttpResponse('校验成功')
else:
print(myform.cleaned_data)
#校验失败的信息,myform.errors 可以当成一个字典,它是所有错误信息{name:[列表,]}
# 每个字段.errors 是一个列表,表示每个字段的错误信息
print(myform.errors)
return HttpResponse('校验失败')

  方法总结:

  • myform.clean_data 验证通过的数据
  • myform.errors 错误数据的对象
  • myform.errors.as_data 错误数据的信息

3,渲染模板

  form组件可以在视图函数中使用,也可以在前端模板中使用。我们展示一下视图层和模板层。

视图层:

# 视图层:
def index(request):
myform = Myform()
return render(request,'index.html',local())

  

模板层:

# 模板层
# 1.渲染方式一:
<form action='' method='post'>
用户名:{{myform:name}} <br>
<input type='submit' value = '提交'></input>
</form>
# 这里的{{myform:name}} 和你写input框是一样的效果,就是属性比input框多一点 # 2.渲染方式二(推荐使用):
<form action='' method='post'>
{% for foo in myform%}
{{ foo.lable }} : {{ foo }} <br>
<input type='submit' value = '提交'></input>
</form>
# 页面显示都是一样的,foo.lable不是用户名,是name,但是可以在创建Myform类时,在CharFiel中添加lable='用户名',这样就行了。 # 3.渲染方式三:
<form action='' method='post'>
{{ myform.as_p }}
<input type='submit' value = '提交'></input>
</form>

  下面举3个例子,详细说一下这三种渲染方式

3.1  form组件的渲染方式1

  html代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <form action="" method="post">
{% csrf_token %}
<p>username: <input type="text" name="name"></p>
<p>password:<input type="text" name="pwd"></p>
<p>re_password:<input type="text" name="r_pwd"></p>
<p>email:<input type="text" name="email"></p>
<p>telephone: <input type="text" name="tel"></p>
<p><input type="submit"></p>
</form> <hr>
<h3>渲染方式1 form组件的渲染</h3>
<form action="" method="post">
{% csrf_token %}
<p>username:
{{ form.name }}
</p>
<p>password:
{{ form.pwd }}
</p>
<p>re_password:
{{ form.r_pwd }}
</p>
<p>email:
{{ form.email }}
</p>
<p>telephone:
{{ form.tel }}
</p>
<p><input type="submit"></p>
</form> </body>
</html>

  views.py

from django.shortcuts import render,HttpResponse

# Create your views here.

from django import forms

class UserForm(forms.Form):
name = forms.CharField(min_length=3)
pwd = forms.CharField(min_length=3)
r_pwd = forms.CharField(min_length=3)
email = forms.EmailField()
# 手机号码的规则固定为11位,***
tel = forms.CharField(min_length=3) def reg(request):
if request.method == 'POST':
# print(request.POST)
# form = UserForm({'name': 'yuan', 'email': '123'})
# print(form.is_valid()) form = UserForm(request.POST)
print(form.is_valid())
if form.is_valid():
print(form.cleaned_data)
else:
print(form.errors) return HttpResponse("OK") form = UserForm() return render(request, 'form/reg.html', locals())

  

3.2  form组件渲染方式2

  如果变量太多了,我们不可能这样写很多个,所以我们使用for循环。

<hr>
<h3>渲染方式2 form组件的渲染</h3>
<form action="" method="post">
{% csrf_token %}
{% for foo in form %}
<div>
<label for="">{{ foo.label }}</label>
{{ foo }}
</div>
{% endfor %} <p><input type="submit"></p>
</form>

  我们可以在form函数里面设置label标签:

class UserForm(forms.Form):
name = forms.CharField(min_length=3, label='用户名')
pwd = forms.CharField(min_length=3, label='密码')
r_pwd = forms.CharField(min_length=3, label='确认密码')
email = forms.EmailField( label='邮箱')
# 手机号码的规则固定为11位,***
tel = forms.CharField(min_length=3, label='电话')

  

3.3  form组件渲染方式3

<hr>
<h3>渲染方式3 form组件的渲染</h3>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }} <p><input type="submit"></p>
</form>

  但是这种方式不推荐使用。因为其固定死了格式。简单测试的时候可以使用。

  三种效果都一样,结果也是,这里就不再展示了。我们推荐使用第二种渲染方式。

4,form组件渲染错误信息

  当返回请求的数据失败的时候,我们如何渲染错误信息

<form action='' method='post'>
{% for foo in myform%}
{{ foo.lable }} : {{ foo }} <span>{{foo.errors.0}}</span><br>
<input type='submit' value = '提交'></input>
</form>

 举个例子:

  视图函数:

def register(request):

    if request.method=="POST":
form=UserForm(request.POST)
if form.is_valid():
print(form.cleaned_data) # 所有干净的字段以及对应的值
else:
print(form.cleaned_data) #
print(form.errors) # ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors.get("name")) # ErrorList ["错误信息",]
return render(request,"register.html",locals())
form=UserForm()
return render(request,"register.html",locals())

  模板:

<form action="" method="post" novalidate>
{% csrf_token %} {% for field in form %}
<div>
<label for="">{{ field.label }}</label>
{{ field }} <span class="pull-right" style="color: red">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<input type="submit" class="btn btn-default"> </form>

  

5,Form组件校验的局部钩子和全局钩子

5.1,什么是局部钩子

  定义一个函数,名字叫:clean_字段名字,内部,取出该字段,进行校验。如果通过,将该字段返回,如果失败,抛出异常(ValidationError)。

  其中ValidationError的异常类型需要引入:

from django.core.exceptions import ValidationError

  

5.2,局部钩子的源码分析

  首先,我们分析一段源码。关于钩子函数:

  从is_valid()点进去,然后点击errors:(也就是 form/forms.py的源码)

我们可以看到下面:

  点进去full_clean(),然后查看_clean_filed_() 方法

  注意(看源码诀窍):看源码的时候,看不懂就过!!

  这里我们查看_clean_fields()函数,这是局部钩子的应用

  首先,从fileds字段中导入其内容,当没有问题的时候,尝试判断其是否合法,如果合法的话,我们将vlaue字段赋值给 cleaned_data[name],然后利用一个反射函数,尝试调用局部钩子,如果有局部钩子函数,我们调用并执行,如果校验成功,我们将name 的值返回到clean_data,并写入clean_data字典中,也就是更新字典,如果出错的话,就抛出异常,将异常信息以键值对({'name': value} 写入 errors 字典中)。

  如果出错的话,局部钩子抛出的异常会添加到该字段中的错误信息,我们在前台获取错误信息的方法如下:

    for循环生成 input 框

    {{ foo.errrs.0 }}

  

5.3,局部钩子示例:

 # 函数名称必须以 claen_字段名  的格式
def clean_name(self):
# 目的:如果用户名已经注册,则报异常
val = self.cleaned_data.get('name') ret = UserInfo.objects.filter(name=val)
if not ret:
return val
else:
raise ValidationError('用户名已经被注册') def clean_tel(self):
# 目的:校验手机号码长度为11
val = self.cleaned_data.get('tel') if len(val) == 11:
return val
else:
raise ValidationError("手机号码格式错误")

5.4,什么是全局钩子

  在写注册用户的时候,有输入密码,确认密码,可以进行布局钩子处理,处理完毕是不是在进行判断,判断其是否相等,相等的话就存到数据库中,不相等就抛出异常。

  全局钩子主要应用场景就是每次校验多个字段,而局部钩子每次取的是单个字段,单个变量。

5.5,全局钩子的源码分析

  下面继续分析一段源码。

  从cleaned_data() 点击进去,我们会发现 clean_form执行的方法是 clean()方法。

  下面我们看clean()方法:

  我们会发现 默认的clean()方法什么都没有写,直接返回的一个 cleaned_data!!所以这就是给我们写的,让我们覆盖的东西。

  为什么这么说呢?

  我们会发现,点进去类 UserInfo中 forms.Form继承基类方法BaseForm。

  而我们所写的全局钩子中 clean_data也是在基类BaseForm里面。所以代码会先去我们所写的类中找clean()方法,如果没有的话,再继续执行下一步。

  校验成功的话,和局部钩子一样,更新字段值,并返回到clean_data字典里面。但是校验失败的话,抛出的异常和局部钩子有点不一样,他是将异常信息以键值对({'__all__': [value, ]}) 写入errors字典中。全局钩子抛出的异常会添加到__all__里面,所以我们在后台获取异常信息

  后台获取错误信息是这样的:

errors = form.errors.get('__all__')
myforms.errors.get('__all__')[0]

  注意先判断上面的 errors 是否存在,存在的话,在前台获取错误信息如下:

{{ myforms.errors.__all__.0 }}

  

5.6,全局钩子示例:

# 函数名称必须命名为clean
def clean(self):
pwd = self.cleaned_data.get('pwd')
r_pwd = self.cleaned_data.get('r_pwd')
# 首先判断是否都通过检测,都不为空,再进行校验
if pwd and r_pwd:
if pwd == r_pwd:
# 如果两次密码相同,则返回干净的字典数据
return self.cleaned_data
else:
# 没通过检测,则返回异常信息
ValidationError('两次密码不一致')
else:
# 如果获取的两个变量中,但凡有一个为空,我们就不需要校验了
return self.cleaned_data

  

5.7,一个完整的forms组件校验

  这里代码主要展示了视图层和form组件和HTML代码。当然前提是我们需要有UserInfo这个数据库。算了还是展示一下models函数吧

  models.py

from django.db import models

# Create your models here.

class UserInfo(models.Model):
name = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
email = models.EmailField()
tel = models.CharField(max_length=32)

  

  MyForms.py

from django import forms

from django.forms import widgets
from form_demo.models import UserInfo from django.core.exceptions import ValidationError class UserForm(forms.Form):
name = forms.CharField(min_length=3, label='用户名',
error_messages={'required': '用户名最短是3位!!'},
widget=widgets.TextInput(attrs={'class': 'form-control'}))
pwd = forms.CharField(min_length=3, label='密码',
error_messages={'required': '密码最短是3位!!'},
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
r_pwd = forms.CharField(min_length=3, label='确认密码',
error_messages={'required': '密码最短是3位!!'},
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
email = forms.EmailField(label='邮箱',
error_messages={'required': '不符合邮箱格式!!'},
widget=widgets.TextInput(attrs={'class': 'form-control'}))
# 手机号码的规则固定为11位,***
tel = forms.CharField(min_length=3, label='电话',
widget=widgets.TextInput(attrs={'class': 'form-control'})) # 函数名称必须以 claen_字段名 的格式
def clean_name(self):
# 目的:如果用户名已经注册,则报异常
val = self.cleaned_data.get('name') ret = UserInfo.objects.filter(name=val)
if not ret:
return val
else:
raise ValidationError('用户名已经被注册') def clean_tel(self):
# 目的:校验手机号码长度为11
val = self.cleaned_data.get('tel') if len(val) == 11:
return val
else:
raise ValidationError("手机号码格式错误") # 函数名称必须命名为clean
def clean(self):
pwd = self.cleaned_data.get('pwd')
r_pwd = self.cleaned_data.get('r_pwd')
# 首先判断是否都通过检测,都不为空,再进行校验
if pwd and r_pwd:
if pwd == r_pwd:
# 如果两次密码相同,则返回干净的字典数据
return self.cleaned_data
else:
# 没通过检测,则返回异常信息
ValidationError('两次密码不一致')
else:
# 如果获取的两个变量中,但凡有一个为空,我们就不需要校验了
return self.cleaned_data

  

  views.py

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.

from form_demo.Myforms import UserForm

def reg(request):
if request.method == 'GET':
form = UserForm()
return render(request, 'form/reg.html', locals()) elif request.method == 'POST':
# form 表单的 name 属性值应该与forms组件字段名称一致
form = UserForm(request.POST)
print(form.is_valid())
# print(forms.clean)
if form.is_valid():
print(form.cleaned_data)
# 校验全部通过,创建数据时,从clean_data中获取数据,
# 但是必须将其中多于的数据pop掉,如下面代码
# myform.cleaned_data.pop('re_pwd')
# models.User.objects.create(**myform.cleaned_data)
return redirect('http://www.baidu.com')
else:
all_error = form.errors.get('__all__')
if all_error:
all_error = all_error[0]
print(form.errors)
print(form.errors.get('__all__'))
# return render(request, 'form/reg.html', locals()) return render(request, 'form/reg.html', locals())

  

 reg.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head>
<body> <hr>
<hr> <div class="container">
<div class="row">
<div class="col-md-6 col-lg-offset-3">
<form action="" method="post">
{% csrf_token %}
<p><label>{{ form.name.label }}</label>
{{ form.name }}<span class="pull-right error">{{ form.name.errors.0 }}</span>
</p>
<p><label>{{ form.pwd.label }}</label>
{{ form.pwd }}<span class="pull-right error">{{ form.pwd.errors.0 }}</span>
</p>
<p><label>{{ form.r_pwd.label }}</label>
{{ form.r_pwd }}<span class="pull-right error">{{ form.r_pwd.errors.0 }}</span><span>{{ all_error }}</span>
</p>
<p><label>{{ form.email.label }}</label>:
{{ form.email }}<span class="pull-right error">{{ form.email.errors.0 }}</span>
</p>
<p><label>{{ form.tel.label }}</label>:
{{ form.tel }}<span class="pull-right error">{{ form.tel.errors.0 }}</span>
</p>
<p><input type="submit"></p>
</form>
</div> </div>
</div> </body>
</html>

  

 我们展示一下效果。

1,我们给数据库存入james这个名字,然后注册james,我们在前端看效果:

2,我们注册电话号码为5位,我们在前端看效果:

3,我们注册密码和确认密码不一致的时候,我们在前端看效果:

参考文献:https://www.cnblogs.com/JetpropelledSnake/p/9397889.html#top(局部钩子和全局钩子,本来我放的代码,但是百度找到了这位老铁画的图的,就借花献佛,直接拿来用了,自己再加以详细的解释)

https://www.cnblogs.com/yuanchenqi/articles/7638956.html

Django学习笔记(14)——AJAX与Form组件知识补充(局部钩子和全局钩子详解)的更多相关文章

  1. 【学习笔记】薛定谔的喵咪Cat—球盒问题(全详解)

    [学习笔记]薛定谔的喵咪Cat-球盒问题(全详解) [题目描述] 当一个猫在盒子里时,因为放射物的状态我们不知道,所以猫的状态我们也不知道,这就所谓猫的生死纠缠态,也是所谓的薛定谔的猫. 当我们做需要 ...

  2. Django学习笔记(6)——Form表单

    知识储备:HTML表单form学习 表单,在前端页面中属于最常见的一个东西了.基本上网站信息的提交都用到了表单,所以下面来学习Django中优雅的表单系统:Form 表单的主要作用是在网页上提供一个图 ...

  3. Django学习笔记之Ajax与文件上传

      Ajax简介 AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”.即使用Javascript语言与服务器进行异步交互,传输 ...

  4. Django学习笔记之Ajax入门

    AJAX准备知识:JSON 什么是 JSON ? JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 JS ...

  5. Django学习笔记(16)——扩展Django自带User模型,实现用户注册与登录

    一,项目题目:扩展Django自带User模型,实现用户注册与登录 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册,登录,用户认证,注销,修改密码等功能. ...

  6. Django学习笔记之form组件的局部钩子和全局钩子

    本文通过注册页面的form组件,查看其中使用的全局钩子和局部钩子. # Create your views here. class RegForm(forms.Form): username = fo ...

  7. Django学习笔记(13)——Django的用户认证(Auth)组件,视图层和QuerySet API

    用户认证组件的学习 用户认证是通过取表单数据根数据库对应表存储的值做比对,比对成功就返回一个页面,不成功就重定向到登录页面.我们自己写的话当然也是可以的,只不过多写了几个视图,冗余代码多,当然我们也可 ...

  8. Django学习笔记(20)——BBS+Blog项目开发(4)Django如何使用Bootstrap

    本文学习如何通过Django使用Bootstrap.其实在之前好几个Django项目中已经尝试使用过了Bootstrap,而且都留有学习记录,我已经大概有了一个大的框架,那么本文就从头再走一遍流程,其 ...

  9. Django学习笔记(18)——BBS+Blog项目开发(2)主体思路及流程

    这篇博客主要完成一个BBS+Blog项目,那么主要是模仿博客园的博客思路,使用Django框架进行练习. 准备:项目需求分析 在做一个项目的时候,我们首先做的就是谈清楚项目需求,功能需求,然后才开始写 ...

随机推荐

  1. SEH hook 的一种方法

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 技术学习来源:火哥(QQ:471194425) 该方法的一些原理暂 ...

  2. EF中获取当前上下文的表名

    EF在处理并发上并不是很好,很多时候我们需要手动写sql操作数据库.但是在基类中我们如何获取当前服务仓储操作的表呢? 使用正则是其中一种解决办法 Repository.Table是一条查询语句,通过t ...

  3. Java日期时间API系列4-----Jdk7及以前的日期时间类的线程安全问题

    1.Date类为可变的,在多线程并发环境中会有线程安全问题. (1)可以使用锁来处理并发问题. (2)使用JDK8  Instant 或 LocalDateTime替代. 2.Calendar的子类为 ...

  4. 怎样深入学习php,成为php高手!?

    本文章开头我想问一句话:PHP是做什么的? 因为这是面试中会问到的一个问题,虽然它看起来很简单,回答做网站的,也就是个简单建站的水平.回答做网站后端开发的,对PHP有了一定的认识,回答做后端处理的,有 ...

  5. SAP MM MB5L 报表里的差异金额如何调整?

    SAP MM MB5L 报表里的差异金额如何调整? 5月3号,收到财务顾问提出的一个问题,说是MB5L报表里有差异. 如下查询条件, 报表结果里显示有差异, 经查,导致这个差异的原因之一是,一些物料批 ...

  6. tomcat配置通过域名访问项目

    tomcat配置通过域名访问项目,是修改conf/server.xml里面的配置信息实现.具体如下: (1)修改Connector节点的port属性值 <Connector port=" ...

  7. PHP代码篇(七)--PHP及MySQL已经使用过的函数

    一.PHP常用函数 //数组转字符串 $str = implode(',',$device_string); //字符串转数组 $arr = explode(',',$device_string); ...

  8. 2.idea安装JavaCC插件.md

      eclipse中插件安装JavaCC插件请参考博客:https://blog.csdn.net/qq_29232943/article/details/62439283   接下来是在idea中安 ...

  9. win10输入法问题,已禁止IME 问题解决

    第一种较为简单的解决方法: windows+R打开「运行」,然后打ctfmon,确定. 另外一种解法: windows的老bug了解决办法: 1. I. WIN + X 打开控制面板 -> 管理 ...

  10. GPU驱动安装&cuda

    版权声明:本文为博主原创文章,支持原创,转载请附上原文出处链接和本声明.  本文链接地址:https://www.cnblogs.com/wannengachao/p/11947668.html 驱动 ...