Django study notes (14) - AJAX components and Form supplementary knowledge (local and global hook hook Detailed)

   Before I made a note on AJAX and form components can refer to: Django study notes (8) - Taiwan before and after the actual data exchange (AJAX) ; Django study notes (6) - Form Form

 

  I felt like I was writing Django notes (8), I just have a cursory knowledge of AJAX, to understand its two main advantages, partial refresh and asynchronous interaction. Form component knowledge While most are aware, but not very clear about the local and global hooks hook. He left a pit, so in later learning, and will definitely encounter.

  Now, I feel like the data on the interaction of Django and AJAX clear understanding of this part, and the hook Form thorough understanding of the components also. Deliberately make a note recording their own learning process. Also in Django notes (8) when said, I will clear this content management, I will write an easy to understand article consolidate, and this document is.

  Now I will AJAX knowledge were notes that he has done, Form hook assembly of local and global hook notes show it. Local and global hooks hooks which have made the source code analysis, in order to better understand the principle of it.

 

AJAX knowledge

1, AJAX request header common contentType

  Data sent, but also successfully resolved the server makes sense. Python built automatically resolve common data format function. Server typically acquisition message body of the request header is coded according to the manner in which the request headers (headers) in the Content-Type field, and then parses the subject. So it comes to data submitted POST program includes Content-Type and a message body encoding two parts.

  Here we take a look at the Content-Type ajax POST request. Beginning with the application media type format:

application / xhtml + xml: XHTML format 

application / xml: XML data format 

application / atom + xml: Atom XML syndication format    

application / json: JSON data format 

application / pdf: pdf format 

application / msword: Word document format 

application / octet-stream : binary stream data (such as the common file download) 

file application / X-WWW-form-urlencoded: 
<form encType = ""> the default encType, form form data is encoded as a key / value format 
to the server (form default submit data format)

  ContentType refers to a coding type of the request body, There are three common:

1.1,application/x-www-form-urlencoded

  This should be the most common way to POST submit the data. Native Form Submit browser default <form> embodiment, if enctype attribute is not set, then the final data will be submitted to application / x-www-form-urlencoded manner. Request similar to the following (independent of the request header are herein omitted):

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

user=james&age=24

  

  Use the following default parameters are summarized as follows:

data: Current ajax request to carry data, an object which is the object, ajax method will default to 
its encoded into a format (urlencoded:? a = 1 & b = 2) is sent to the server; Further, ajax default to get side 
type transmission request. 
 
contentType: "application / x-www -form-urlencoded". When the server transmits content information to the 
encoding type. Data encoding format specified for the current request; urlencoded:? A = 1 & b = 2;

  

 

1.2,multipart/form-data

  This is a common way of POST data submitted. When we use the form to upload files, you must make the form of equal enctype multipart / form-data.

  Direct look at an example:

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--

  This example is slightly more complex, generates the first boundary for dividing a different field, in order to avoid repeated text content, very long and complicated boundary. Then Content-Type indicates the data is in multipart / form-data encoded.

  boundary of this request is to what?

  Message body in accordance with the number of fields is divided into a plurality of similar structural parts, each part are based --boundary begin. Followed by the content description information, then the transport, the last field is the specific content (text or binary). If the file is transmitted, but also contains the text name and file type information. Finally, in order to identify the body of the message --boundary-- end. Detailed definition of multipart / form-data, go to the View rfc 1967.

  This approach is generally used to upload files, the major server-side language it also has a good support.

  Both methods POST data mentioned above, are native browser support, but at this stage the standard form only natively supports both. In fact enctype also supports text / plain, but with very little.

  After As more and more Web sites, especially WebAPP, all use AJAX for data exchange, we can define new data is presented in a way, to the developers bring more convenience.

 

1.3,application/json

  application / json this Content-Type response header as I am sure you are not familiar with. In fact, now more and more people now request him as head, used to tell the server message body is serialized JSON string. Due to popular JSON specification, low processing outside the major version of IE browsers support JSON.stringify native, server-side language also has a function of processing JSON, JSON does not use any trouble.

 

  Such default parameters of the above-described form, the data CSRF cross-site request forgery middleware This pair is identified automatically, as well as the ContentType parameter will form, as follows:

contentType: "application / json", the server also transmits a json string. 
 
Note: contentType: "application / json" Once set, data must be json string, the object can not be json

  This type using request.POST not display this type to be used request.body to display data.

1.4, text / xml (not used)

  Compared to JSON, XML can not be better suited for data interchange, it contains too much packaging, and it does not match the data model with most programming languages, so most programmers surprised, XML is a data-oriented, JSON and object-oriented structure, which gives the programmer a more intimate feel.

  We are now generally used like this:

  • 1, XML data storage storing configuration files where necessary using structured storage;
  • 2, data transfer, data exchange using JSON

  Here is ajax Content-Type is text / xml request:

 

2, file upload

  Note: When we use the form to upload files, you must make the form of equal enctype multipart / form-data.

2.1   -based file upload form form

  html code:

<!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/[email protected]/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

Guess you like

Origin www.cnblogs.com/wj-1314/p/10929251.html