1.分页功能1.1批量插入数据

# 批量插入数据 book_list = [] for i in range(100): book = Book(title="book_%s"%i,price=i*i,publishDate="2012-12-12",publish_id=1) book_list.append(book) Book.objects.bulk_create(book_list)1.2Paginator

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger book_list = Book.objects.all() paginator = Paginator(book_list, 10) # 每页显示10条数据 print(paginator.count) # 总数据数 105 print(paginator.num_pages) # 总页数 11 print(paginator.page_range) # 页码的列表 range(1, 12) page1 = paginator.page(1) # 第一页的book对象列表 print(page1) # <Page 1 of 11> for i in page1: # 遍历第一页的所有数据对象 print(i) # Book object (16) print(page1.object_list) # 第一页的所有数据[<Book: Book object (7)>, ... <Book: Book object (16)>] page2 = paginator.page(2) print(page2.has_next()) # 是否有下一页 True print(page2.next_page_number()) # 下一页的页码 3 print(page2.has_previous()) # 是否有上一页 True print(page2.previous_page_number()) # 上一页的页码 1 # 抛错 page=paginator.page(12) # error:EmptyPage page=paginator.page("z") # error:PageNotAnInteger1.3分页案例

views.py

from django.shortcuts import render,HttpResponsefrom django.core.paginator import Paginator,EmptyPagefrom app1.models import *def index(request): book_list = Book.objects.all() paginator = Paginator(book_list, 7) # 每页显示7条数据 current_page = int(request.GET.get("page", 1)) # 没有page这个key,就设置为1# 这里是保证当前最多只显示11个页码 if paginator.num_pages > 11: if current_page-5<1: page_range = range(1,12) elif current_page+5>paginator.num_pages: page_range = range(paginator.num_pages-10,paginator.num_pages+1) else: page_range = range(current_page - 5, current_page + 6) else: page_range = paginator.page_range # 显示当前页的book对象列表 try: current_page_contents = paginator.page(current_page) # 如果数据为空,显示第一页的数据 except EmptyPage as e: current_page_contents = paginator.page(1) return render(request, "index.html",locals())

index.html

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title> </title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh5u" crossorigin="anonymous"> <script type="text/javascript" src="/static/jquery-3.3.1.js"></script></head><body><ul> {% for book_obj in current_page_contents %} <li>{{ book_obj.title }}--{{ book_obj.price }}</li> {% endfor %}</ul><nav aria-label="Page navigation"> <ul class="pagination">{# 当前页有上一页的时候,才可点击#} {% if current_page_contents.has_previous %} <li><a href="?page={{ current_page_contents.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">上一页</span> </a></li> {% else %} <li class="disabled"><a href="" aria-label="Previous" > <span aria-hidden="true">上一页</span> </a></li> {% endif %} {% for page_num in page_range %}{# 前面的内容就是当前访问的url#} {% if page_num == current_page %} <li class="active"><a href="?page={{ page_num }}">{{ page_num }}</a></li> {% else %} <li><a href="?page={{ page_num }}">{{ page_num }}</a></li> {% endif %} {% endfor %} {% if current_page_contents.has_next %} <li><a href="?page={{ current_page_contents.next_page_number }}" aria-label="Next"> <span aria-hidden="true">下一页</span> </a></li> {% else %} <li class="disabled"><a href="" aria-label="Next"> <span aria-hidden="true">下一页</span> </a></li> {% endif %} </ul></nav></body><script type="text/javascript"></script></html>



2.forms组件

作用:主要是校验字段功能2.1简单form

注意:1.即使不是所有字段验证通过,form.cleaned_data中也有通过验证的字段的值。2.前端传过来的字段可以比UserForm中的字段多,多余的字段不进行验证。所有字段验证通过,form.is_valid()返回true。3.前端传过来的字段比UserForm中的字段少,form.is_valid()返回false。

forms.py

#!/usr/bin/env python# -*- coding:utf-8 -*-# Author: vitafrom django import formsclass UserForm(forms.Form): name = forms.CharField(min_length=4, label="用户名", error_messages={"required": "该字段不能为空"}) pwd = forms.CharField(min_length=4, label="密码", error_messages={"required": "该字段不能为空"}) r_pwd = forms.CharField(min_length=4, label="确认密码", error_messages={"required": "该字段不能为空"}) email = forms.EmailField(label="邮箱" , error_messages={"required": "该字段不能为空", "invalid": "格式错误"}) tel = forms.CharField(label="手机号")

views.py

from django.shortcuts import render,HttpResponsefrom django.core.paginator import Paginator,EmptyPagefrom app1.models import *from app1.myforms import *def index(request): if request.method=="POST": print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['UlDvceNfBeKeeVdyj8ot6YScOg5MQM7R9kW7pULdq0G7z8D5ZNjuUlYQI4bGh7ku'], 'name': ['123'], 'pwd': ['123'], 'r_pwd': ['123'], 'email': ['123'], 'tel': ['123']}> form = UserForm(request.POST) if form.is_valid(): print("form.cleaned_data----", form.cleaned_data) else: print("form.cleaned_data----", form.cleaned_data) # {'pwd': '1234', 'email': '123@qq.com', 'tel': '123'} print("form.errors----", form.errors) print("type(form.errors)----", type(form.errors)) # <class 'django.forms.utils.ErrorDict'> print("form.errors.get('name')----", form.errors.get("name")) # <ul class="errorlist"><li>该字段不能为空</li></ul> print("type(form.errors.get('name'))----", type(form.errors.get("name"))) # <class 'django.forms.utils.ErrorList'> print("form.errors.get('name')[0]----", form.errors.get("name")[0]) return render(request, "index.html", locals())

index.html

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title> </title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh5u" crossorigin="anonymous"> <script type="text/javascript" src="/static/jquery-3.3.1.js"></script></head><body><div class="row"> <div class="col-md-6 col-md-offset-3"> <h4>简单form</h4> <form action="" method="post" > {% csrf_token %} <div class="form-group"> <label for="user_id">用户名</label> <input type="text" id="user_id" class="form-control" name="name"> </div> <div class="form-group"> <label for="user_id">密码</label> <input type="text" id="user_id" class="form-control" name="pwd"> </div> <div class="form-group"> <label for="user_id">确认密码</label> <input type="text" id="user_id" class="form-control" name="r_pwd"> </div> <div class="form-group"> <label for="user_id">邮箱</label> <input type="text" id="user_id" class="form-control" name="email"> </div> <div class="form-group"> <label for="user_id">手机号</label> <input type="text" id="user_id" class="form-control" name="tel"> </div> <input type="submit"> </form> </div></div></body><script type="text/javascript"></script></html>


2.2form三种渲染方式

forms.py

#!/usr/bin/env python# -*- coding:utf-8 -*-# Author: vitafrom django import formsfrom django.forms import widgetsclass UserForm(forms.Form): # 自定义html中的标签和添加类 name = forms.CharField(min_length=4, label="用户名", error_messages={"required": "该字段不能为空"},widget=widgets.TextInput(attrs={"class": "form-control"})) pwd = forms.CharField(min_length=4, label="密码", error_messages={"required": "该字段不能为空"},widget=widgets.PasswordInput(attrs={"class": "form-control"})) r_pwd = forms.CharField(min_length=4, label="确认密码", error_messages={"required": "该字段不能为空"},widget=widgets.PasswordInput(attrs={"class": "form-control"})) email = forms.EmailField(label="邮箱", error_messages={"required": "该字段不能为空", "invalid": "格式错误"},widget=widgets.EmailInput(attrs={"class": "form-control"})) tel = forms.CharField(label="手机号", widget=widgets.TextInput(attrs={"class": "form-control"}))

views.py

from django.shortcuts import render,HttpResponsefrom django.core.paginator import Paginator,EmptyPagefrom app1.models import *from app1.myforms import *def index(request): form = UserForm() if request.method=="POST": print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['UlDvceNfBeKeeVdyj8ot6YScOg5MQM7R9kW7pULdq0G7z8D5ZNjuUlYQI4bGh7ku'], 'name': ['123'], 'pwd': ['123'], 'r_pwd': ['123'], 'email': ['123'], 'tel': ['123']}> form = UserForm(request.POST) if form.is_valid(): print("form.cleaned_data----", form.cleaned_data) else: print("form.cleaned_data----", form.cleaned_data) # {'pwd': '1234', 'email': '123@qq.com', 'tel': '123'} print("form.errors----", form.errors) print("type(form.errors)----", type(form.errors)) # <class 'django.forms.utils.ErrorDict'> print("form.errors.get('name')----", form.errors.get("name")) # <ul class="errorlist"><li>该字段不能为空</li></ul> print("type(form.errors.get('name'))----", type(form.errors.get("name"))) # <class 'django.forms.utils.ErrorList'> print("form.errors.get('name')[0]----", form.errors.get("name")[0]) return render(request, "index.html", locals())2.2.1渲染方式1

index.html

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title> </title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh5u" crossorigin="anonymous"> <script type="text/javascript" src="/static/jquery-3.3.1.js"></script></head><body><div class="row"> <div class="col-md-6 col-md-offset-3"> <h4>form组件渲染方式1</h4> <form action="" method="post" > {% csrf_token %} <div class="form-group"> <label>{{ form.name.label }}</label> {{ form.name }} <span class="pull-right error">{{ form.name.errors.0 }}</span> </div> <div class="form-group"> <label>{{ form.pwd.label }}</label> {{ form.pwd }} <span class="pull-right error">{{ form.pwd.errors.0 }}</span> </div> <div class="form-group"> <label>{{ form.r_pwd.label }}</label> {{ form.r_pwd }} <span class="pull-right error">{{ form.r_pwd.errors.0 }}</span> </div> <div class="form-group"> <label>{{ form.email.label }}</label> <!--错误信息--> {{ form.email }} <span class="pull-right error">{{ form.email.errors.0 }}</span> </div> <div class="form-group"> <label for="user_id">手机号</label> {{ form.tel }} <span class="pull-right error">{{ form.tel.errors.0 }}</span> </div> <input type="submit"> </form> </div></div></body><script type="text/javascript"></script></html>


2.2.2渲染方式2

index.html

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title> </title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh5u" crossorigin="anonymous"> <script type="text/javascript" src="/static/jquery-3.3.1.js"></script></head><body><div class="row"> <div class="col-md-6 col-md-offset-3"> <h4>form组件渲染方式2</h4> <form action="" method="post" > {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="">{{ field.label }}</label> {{ field }} </div> {% endfor %} <input type="submit"> </form> </div></div></body><script type="text/javascript"></script></html>


2.2.3渲染方式3

index.html

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title> </title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh5u" crossorigin="anonymous"> <script type="text/javascript" src="/static/jquery-3.3.1.js"></script></head><body><div class="row"> <div class="col-md-6 col-md-offset-3"> <h4>form组件渲染方式3</h4> <form action="" method="post" > {% csrf_token %} {{ form.as_p }} <input type="submit"> </form> </div></div></body><script type="text/javascript"></script></html>


2.3form组件局部钩子

# 局部钩子函数名为clean_UserForm中字段名# 返回值为val,报错时raise ValidationError("用户名长度最长为12")# 错误信息存放在form.errors.get("字段名")[0]def clean_name(self): val = self.cleaned_data.get("name") if len(val)<12: return val else: raise ValidationError("用户名长度最长为12")

查看源码

form.is_valid() def is_valid(self): """Return True if the form has no errors, or False otherwise.""" return self.is_bound and not self.errors @property def errors(self): """Return an ErrorDict for the data provided for the form.""" if self._errors is None: self.full_clean() return self._errors def full_clean(self): """ Clean all of self.data and populate self._errors and self.cleaned_data. """ self._errors = ErrorDict() if not self.is_bound: # Stop further processing. return self.cleaned_data = {} # 是一个字典 # If the form is permitted to be empty, and none of the form data has # changed from the initial data, short circuit any validation. if self.empty_permitted and not self.has_changed(): return self._clean_fields() #局部钩子所在源码处,先执行局部钩子函数,然后执行全局钩子函数 self._clean_form() #全局钩子所在源码处 self._post_clean() def _clean_fields(self): for name, field in self.fields.items(): # value_from_datadict() gets the data from the data dictionaries. # Each widget type knows how to retrieve its own data, because some # widgets split data over several HTML fields. if field.disabled: value = self.get_initial_for_field(field, name) else: value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) try: if isinstance(field, FileField): initial = self.get_initial_for_field(field, name) value = field.clean(value, initial) else: value = field.clean(value) self.cleaned_data[name] = value #可以看到,验证通过的字段赋值给了cleaned_data. if hasattr(self, 'clean_%s' % name): value = getattr(self, 'clean_%s' % name)() self.cleaned_data[name] = value except ValidationError as e: self.add_error(name, e)

2.3.1局部钩子案例

forms.py

#!/usr/bin/env python# -*- coding:utf-8 -*-# Author: vitafrom django import formsfrom django.forms import widgetsfrom django.core.exceptions import ValidationErrorclass UserForm(forms.Form): # 自定义html中的标签和添加类 name = forms.CharField(min_length=4, label="用户名", error_messages={"required": "该字段不能为空"},widget=widgets.TextInput(attrs={"class": "form-control"})) pwd = forms.CharField(min_length=4, label="密码", error_messages={"required": "该字段不能为空"},widget=widgets.PasswordInput(attrs={"class": "form-control"})) r_pwd = forms.CharField(min_length=4, label="确认密码", error_messages={"required": "该字段不能为空"},widget=widgets.PasswordInput(attrs={"class": "form-control"})) email = forms.EmailField(label="邮箱", error_messages={"required": "该字段不能为空", "invalid": "格式错误"},widget=widgets.EmailInput(attrs={"class": "form-control"})) tel = forms.CharField(label="手机号", widget=widgets.TextInput(attrs={"class": "form-control"}))# 局部钩子函数,必须是clean_字段名 def clean_tel(self): val = self.cleaned_data.get("tel") if len(val)==11: return val else: raise ValidationError("手机格式错误") def clean_name(self): val = self.cleaned_data.get("name") if len(val)<12: return val else: raise ValidationError("用户名长度最长为12")

views.py

from django.shortcuts import render,HttpResponsefrom django.core.paginator import Paginator,EmptyPagefrom app1.models import *from app1.myforms import *def index(request): form = UserForm() if request.method=="POST": print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['UlDvceNfBeKeeVdyj8ot6YScOg5MQM7R9kW7pULdq0G7z8D5ZNjuUlYQI4bGh7ku'], 'name': ['123'], 'pwd': ['123'], 'r_pwd': ['123'], 'email': ['123'], 'tel': ['123']}> form = UserForm(request.POST) if form.is_valid(): print("form.cleaned_data----", form.cleaned_data) else: print("form.cleaned_data----", form.cleaned_data) # {'pwd': '1234', 'email': '123@qq.com', 'tel': '123'} print("form.errors----", form.errors) print("type(form.errors)----", type(form.errors)) # <class 'django.forms.utils.ErrorDict'> print("form.errors.get('name')----", form.errors.get("name")) # <ul class="errorlist"><li>该字段不能为空</li></ul> print("type(form.errors.get('name'))----", type(form.errors.get("name"))) # <class 'django.forms.utils.ErrorList'> print("form.errors.get('name')[0]----", form.errors.get("name")[0]) return render(request, "index.html", locals())

index.html

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title> </title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh5u" crossorigin="anonymous"> <script type="text/javascript" src="/static/jquery-3.3.1.js"></script></head><body><div class="row"> <div class="col-md-6 col-md-offset-3"> <h4>forms组件渲染方式1</h4> <form action="" method="post" novalidate> {% csrf_token %} <p>{{ form.name.label }} {{ form.name }} <span class="pull-right error">{{ form.name.errors.0 }}</span> </p> <p>{{ form.pwd.label }} {{ form.pwd }} <span class="pull-right error">{{ form.pwd.errors.0 }}</span> </p> <p>确认密码 {{ form.r_pwd }} <span class="pull-right error">{{ form.r_pwd.errors.0 }}</span><span class="pull-right error">{{ errors.0 }}</span> </p> <p>邮箱 {{ form.email }} <span class="pull-right error">{{ form.email.errors.0 }}</span></p> <p>手机号 {{ form.tel }} <span class="pull-right error">{{ form.tel.errors.0 }}</span></p> <input type="submit"> </form> </div></div></body><script type="text/javascript"></script></html>


2.4form组件全局钩子

# 全局钩子,函数名必须为clean # 返回值是self.cleaned_data,报错时raise ValidationError("两次密码不一致") # 错误信息存放在errors = form.errors.get("__all__").[0] def clean(self): pwd = self.cleaned_data.get("pwd") r_pwd=self.cleaned_data.get("r_pwd") # 当密码验证不通过的时候,假如密码pwd为空,就不要验证密码是否一致了 if pwd and r_pwd: if pwd==r_pwd: return self.cleaned_data else: raise ValidationError("两次密码不一致") else: return self.cleaned_data

全局钩子源码

def _clean_form(self): try: cleaned_data = self.clean() except ValidationError as e: #这里捕获ValidationError,所以自己定义的函数中抛出该异常 self.add_error(None, e) else: if cleaned_data is not None: self.cleaned_data = cleaned_data def clean(self): """ Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named '__all__'. """ return self.cleaned_data #所以我们重写clean方法,返回值为cleaned_data

2.4.1全局钩子案例

forms.py

#!/usr/bin/env python# -*- coding:utf-8 -*-# Author: vitafrom django import formsfrom django.forms import widgetsfrom django.core.exceptions import ValidationErrorclass UserForm(forms.Form): # 自定义html中的标签和添加类 name = forms.CharField(min_length=4, label="用户名", error_messages={"required": "该字段不能为空"},widget=widgets.TextInput(attrs={"class": "form-control"})) pwd = forms.CharField(min_length=4, label="密码", error_messages={"required": "该字段不能为空"},widget=widgets.PasswordInput(attrs={"class": "form-control"})) r_pwd = forms.CharField(min_length=4, label="确认密码", error_messages={"required": "该字段不能为空"},widget=widgets.PasswordInput(attrs={"class": "form-control"})) email = forms.EmailField(label="邮箱", error_messages={"required": "该字段不能为空", "invalid": "格式错误"},widget=widgets.EmailInput(attrs={"class": "form-control"})) tel = forms.CharField(label="手机号", widget=widgets.TextInput(attrs={"class": "form-control"})) def clean_tel(self): val = self.cleaned_data.get("tel") if len(val)==11: return val else: raise ValidationError("手机格式错误") def clean_name(self): val = self.cleaned_data.get("name") if len(val)<12: return val else: raise ValidationError("用户名长度最长为12") # 全局钩子,函数名必须为clean def clean(self): pwd = self.cleaned_data.get("pwd") r_pwd=self.cleaned_data.get("r_pwd") # 当密码验证不通过的时候,假如密码pwd为空,就不要验证密码是否一致了 if pwd and r_pwd: if pwd==r_pwd: return self.cleaned_data else: raise ValidationError("两次密码不一致") else: return self.cleaned_data

vews.py

from django.shortcuts import render,HttpResponsefrom django.core.paginator import Paginator,EmptyPagefrom app1.models import *from app1.myforms import *def index(request): form = UserForm() if request.method=="POST": print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['UlDvceNfBeKeeVdyj8ot6YScOg5MQM7R9kW7pULdq0G7z8D5ZNjuUlYQI4bGh7ku'], 'name': ['123'], 'pwd': ['123'], 'r_pwd': ['123'], 'email': ['123'], 'tel': ['123']}> form = UserForm(request.POST) if form.is_valid(): print("form.cleaned_data----", form.cleaned_data) else: print("form.cleaned_data----", form.cleaned_data) # {'pwd': '1234', 'email': '123@qq.com', 'tel': '123'} print("form.errors----", form.errors) print("type(form.errors)----", type(form.errors)) # <class 'django.forms.utils.ErrorDict'> print("form.errors.get('name')----", form.errors.get("name")) # <ul class="errorlist"><li>该字段不能为空</li></ul> print("type(form.errors.get('name'))----", type(form.errors.get("name"))) # <class 'django.forms.utils.ErrorList'> print("form.errors.get('name')[0]----", form.errors.get("name")[0]) errors = form.errors.get("__all__") print("errors----", errors) # <ul class="errorlist nonfield"><li>两次密码不一致</li></ul> print("type(errors)----", type(errors)) # <class 'django.forms.utils.ErrorList'> return render(request, "index.html", locals())

index.html

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title> </title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh5u" crossorigin="anonymous"> <script type="text/javascript" src="/static/jquery-3.3.1.js"></script></head><body><div class="row"> <div class="col-md-6 col-md-offset-3"> <h4>forms组件渲染方式1</h4> <form action="" method="post" novalidate> {% csrf_token %} <p>{{ form.name.label }} {{ form.name }} <span class="pull-right error">{{ form.name.errors.0 }}</span> </p> <p>{{ form.pwd.label }} {{ form.pwd }} <span class="pull-right error">{{ form.pwd.errors.0 }}</span> </p> <p>确认密码 {{ form.r_pwd }} <span class="pull-right error">{{ form.r_pwd.errors.0 }}</span><span class="pull-right error">{{ errors.0 }}</span> </p> <p>邮箱 {{ form.email }} <span class="pull-right error">{{ form.email.errors.0 }}</span></p> <p>手机号 {{ form.tel }} <span class="pull-right error">{{ form.tel.errors.0 }}</span></p> <input type="submit"> </form> </div></div></body><script type="text/javascript"></script></html>