Django_分页/From表单

分页

1 初试分页

def index(req):
    #自己定义的实现分页的方法一
        per_page_count=10    //设置每页显示的数目
        current_page=1         //默认是第一页
        if req.GET.get('p',None):
            current_page=req.GET.get('p',None)
            current_page=int(current_page) //得到的当前页

       star=(current_page-1)*per_page_count 
       end=current_page*per_page_count//用来做切片求star和end
       data=USER_LIST[star:end]//切片

        up_page=current_page-1 //上一页
        if current_page<=1:
            up_page=1  //如果当前页小于等于1,设置为1
        next_page=current_page+1//下一页
        return render(req,"index.html",{"user_list":data,'up_page':up_page, 'next_page':next_page})                
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    {% for user in  user_list %}

        <li>{{ user.name }} ——{{ user.age }}       </li>
    {% endfor %}

    <a href="/index/?p={{ up_page }}">上一页</a><a href="/index/?p={{ next_page }}">下一页</a>

</ul>

</body>
</html>
html

2 django内置分页

from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

L = []
for i in range(999):
    L.append(i)

def index(request):
    current_page = request.GET.get('p')

    paginator = Paginator(L, 10)
    # per_page: 每页显示条目数量
    # count:    数据总个数
    # num_pages:总页数
    # page_range:总页数的索引范围,如: (1,10),(1,200)
    # page:     page对象
    try:
        posts = paginator.page(current_page)
        # has_next              是否有下一页
        # next_page_number      下一页页码
        # has_previous          是否有上一页
        # previous_page_number  上一页页码
        # object_list           分页之后的数据列表
        # number                当前页
        # paginator             paginator对象
    except PageNotAnInteger:
        posts = paginator.page(1)
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)
    return render(request, 'index.html', {'posts': posts})

views.py
内置分页
USER_LIST=[]
for i in range(1,500):
    temp={"name":"root"+str(i), 'age':i   }
    USER_LIST.append(temp)


class CustomPaginator(Paginator):
    def __init__(self, current_page, per_pager_num, *args, **kwargs):
        try:
            self.current_page=int(current_page)
            self.per_page_num=int(per_pager_num)
        except TypeError as e:
            self.current_page=1
            self.per_page_num = int(per_pager_num)
        super(CustomPaginator, self).__init__(*args, **kwargs)
   //继承父类属性方法
    def page_num_range(self)://自定义返回分页的方式
        if self.num_pages<self.per_page_num:
            return range(1,self.num_pages+1)
        //如果总页数小于当前需要显示的页数,返回1,到总页数的页码
        part=int(self.per_page_num/2)
        //获取当前显示总页数的二分之一,目的为了左移
        if self.current_page<=part:
            return range(1,self.per_page_num+1)
        //如果当前点击的页码小于part(1-6),那么返回1到当前页的页码,+1是因为切片不顾尾
        if self.current_page+part>self.num_pages:
            return range(self.num_pages-self.per_page_num,self.num_pages)
        //如果当前点击的页码+part大于最后一页,说明会多显示无用的页码,返回最后的页码减去要分页的数码, 到最后一页
        return range(self.current_page-part,self.current_page+part+1)
//返回当前页码-part, 到当前页码+part+1
def index1(request):
    current_page = request.GET.get('p')
    paginator=CustomPaginator(current_page,7,USER_LIST,10) #Paginnator对象
    try:
         posts=paginator.page(current_page)
    except PageNotAnInteger:
        posts = paginator.page(1) 
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)

    return render(request, "index1.html",{'posts':posts})                
内置分页拓展
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    {% for user in  posts.object_list %}
        <li>{{ user.name }} ——{{ user.age }}       </li>
    {% endfor %}
</ul>//posts对象.object_list方法里面所有的数据
{#   {% include 'include/include.html' %}#}

{% if posts.has_previous %}
    <a href="/index1/?p={{ posts.previous_page_number }}">上一页</a>
    {% else %}
    <a href="#">上一页</a>
{% endif %}
//如果有上一页显示,否则等于#
{% for i in posts.paginator.page_num_range  %}

    {% if i == posts.number  %}
        <a style="color: burlywood; font-size: 20px" href="/index1/?p={{ i }}">{{ i }}</a>
    {% else %}
        <a href="/index1/?p={{ i }}">{{ i }}</a>
    {% endif %}
//显示自己扩展的page_num_range方法,return的是一个ruage,如果是当前页加属性
{% endfor %}

{% if posts.has_next %}
    <a href="/index1/?p={{ posts.next_page_number }}">下一页</a>
    {% else %}
    <a href="#">下一页</a>
{% endif %}
<span>
    {{ posts.number }}/{{ posts.paginator.num_pages }}
</span>
//当前页/最后一页



</body>
</html>
内置分页html

3、自定义分页

分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。

1、设定每页显示数据条数

2、用户输入页码(第一页、第二页...)

3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置

4、在数据表中根据起始位置取值,页面上输出数据

class Pagination(object):
    def __init__(self, totalCount, currentPage,perPageNum=10,maxPageNum=7):
        #//总数目, 当前页,每页显示的数目,每页显示的页码
        self.totalCout=int(totalCount)
        try:
            v=int(currentPage)
            if v <=0:
                v=1
            self.currentPage=int(v)
            #//如果当前页<0,设置为1
        except Exception as e:
            self.currentPage=1
            #//出错或为空也设置为1
        self.perPageNum = perPageNum
        self.maxPageNum = maxPageNum
        print(self.totalCout,self.currentPage)
    def star(self):
        return (self.currentPage-1)*self.perPageNum
    #//设置开始切片页码,当前页-1 * 每页需要显示的数据
    def end(self):
        return self.currentPage*self.perPageNum
    # //设置结束切片页码,当前页 * 每页需要显示的数据
    @property
    def num_pages(self):
        a,b=divmod(self.totalCout,self.perPageNum)
        if b==0:
            return a
        else:
            return a+1
        #//设置最大页数
    def page_num_range(self):
        #//设置分页方式,见拓展
        if self.num_pages<self.maxPageNum:
            return range(1,self.num_pages+1)
        part=int(self.maxPageNum/2)
        if self.currentPage<=part:
            return range(1,self.maxPageNum+1)
        if self.currentPage+part>self.num_pages:
            return range(self.num_pages-self.maxPageNum+1,self.num_pages+1)

        return range(self.currentPage-part,self.currentPage+part+1)
    def page_str(self):
        first="<li><a href=/index2/?p=1>首页</a></li>"
        list=[]
        list.append(first)
        #//设置首页
        if self.currentPage==1:
            prev = "<li><a href=#>上一页</a</li>>"
        else:
            prev = "<li><a href=/index2/?p=%s>上一页</a></li>"%(self.currentPage-1)
        list.append(prev)
        #//设置上一页
        for i in self.page_num_range():
            if i ==self.currentPage:
                temp = "<li class='active'><a  href=/index2/?p=%s>%s</a></li>" % (i, i)
            else:
                temp="<li><a href=/index2/?p=%s>%s</a></li>"%(i,i)
            list.append(temp)
        # 循环自身的分页方法,
        if self.currentPage==self.num_pages:
            prev2 = "<li><a href=#>下一页</a>"
        else:
            prev2 = "<li><a href=/index2/?p=%s>下一页</a></li>"%(self.currentPage+1)
        list.append(prev2)
        lase="<li><a href=/index2/?p=%s>末页</a></li>"%(self.num_pages)
        list.append(lase)
        # //设置尾页
        return ''.join(list)
自定义分页的类
USER_LIST=[]
for i in range(1,500):
    temp={"name":"root"+str(i), 'age':i   }
    USER_LIST.append(temp)

def index2(req):

    currentPage=req.GET.get("p")

    posts_obj=Pagination(500,currentPage,)
    //传入最大数,和当前页

    data_list = USER_LIST[posts_obj.star():posts_obj.end()]
    //用于切片


    return render(req,"index2.html",{'data_list':data_list,"posts_obj":posts_obj})
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"/>
    <style>

    </style>
</head>
<body>

<ul>
    {% for user in  data_list %}
        <li>{{ user.name }} ——{{ user.age }} </li>
    {% endfor %}
</ul>

    <ul class="pagination">
        <li><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li>
        {{ posts_obj.page_str|safe }}
        <li><a href="#">1</a></li>
        <li><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li>
      </ul>


</body>
</html>
自定义分页html部分

 FROM

Django的Form主要具有一下几大功能

1 生成HTML标签
2 验证用户数据(显示错误信息)
3 HTML Form提交保留上次提交数据
4 初始化页面显示内容

FROM牛刀小试

1创建from类

from django.forms import Form     //引入form
from django import  forms
from django.forms import widgets// 定制生成的html插件
from django.forms import fields  //引入fiedls
 
class MyForm(forms.Form):
//创建一个myform类,继承 forms.Form
    user = fields.CharField(
        widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'})
    )//设置为普通input框, 设置属性id=i1 class=c1
 
    gender = fields.ChoiceField(
        choices=((1, ''), (2, ''),),
        initial=2,
        widget=widgets.RadioSelect
    )//设置radio单选
    #//gender2 = fields.CharField(
        initial=2,
        widget=widgets.RadioSelect(choices=((1, ''), (2, ''),),)
    )//设置radio单选,第二种方式
    
 
    city = fields.CharField(
        initial=2,
        widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
    )//单选select
    city = fields.ChoiceField(
        choices=[(1,'上海'),(2,'北京'),]
        initial=2,
        widget=widgets.Select()
    )//单选select第二种方式
 
    pwd = fields.CharField(
        widget=widgets.PasswordInput(attrs={'class': 'c1'}, 
    render_value=True)
    )
View Code

2、View函数处理

from django.shortcuts import render, redirect
from .forms import MyForm
def index(request):
    if request.method == "GET":
        obj = MyForm()
        return render(request, 'index.html', {'form': obj})
        //第一次提交结果肯定是get返回index.html,同时返回空对象,生成input界面
    elif request.method == "POST":
        obj = MyForm(request.POST, request.FILES)//把from提交的结果和上传的文件验证myfrom
        if obj.is_valid():
            values = obj.clean()
            print(values)
       //如果成功,打印一下值 
        else:
            errors = obj.errors
            print(errors)
        return render(request, 'index.html', {'form': obj})
        //否则把obj返回, 前台调用obj.errors显示错误类型
    else:
        return redirect('http://www.google.com')        
View

3生成HTML

<form novalidate action="/"  method="POST" enctype="multipart/form-data">
//novalidate阻止游览器,enctype="multipart/form-data上传文件必加
    <p>{{ form.user }} {{ form.user.errors }}</p>   
    <p>{{ form.gender }} {{ form.gender.errors }}</p>
    <p>{{ form.city }} {{ form.city.errors }}</p>
    <p>{{ form.pwd }} {{ form.pwd.errors }}</p>
    <input type="submit"/>
</form>
// 第一个变量生成input框, 第二个生成错误信息
html

Form类

创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

1、Django内置字段如下

1.1 field方法

Field
    required=True,                      //是否允许为空
    widget=None,                      //HTML插件
    initial=None,                       //初始值
    label=None,                       // 用于生成Label标签或显示内容
    help_text='',                     //帮助信息(在标签旁边显示),在后面加
    error_messages=None,     //错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    show_hidden_initial=False //是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
    validators=[],               //自定义验证规则
    localize=False,               //是否支持本地化
    disabled=False,              //是否可以编辑,等于ture不可编辑状态
    label_suffix=None/':'       // Label内容后缀 和 input输入框之间,一般用冒号
View Code

1.2CharField(Field)

max_length=None,            // 最大长度
min_length=None,             //最小长度
strip=True                   //是否移除用户输入空白
View Code

1.3IntegerField(Field)

IntegerField(Field)
    max_value=None,             // 最大值
    min_value=None,              //最小值
 //多用于年龄验证
View Code

1.5ChoiceField(Field) //默认单选select,封装了choices方法

    choices=(),                   选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,              是否必填
    widget=None,               插件,默认select插件
    label=None,                  Label内容
    initial=None,                 初始值
    help_text='',                 帮助提示

city=fields.ChoiceField(
        choices=[(1,'济南'),(2,'青岛'),(3,'商河')],
        initial=2 #默认显示第二个,可以在函数里面设置类(【c】)
//obj = TestFrom({'city':3)--函数里面设置
    )
View Code

TypedChoiceField(ChoiceField)//对选中的值进行一次转化

city=fields.ChoiceField(
        # coerce=lambda x: int(x),   #把提交过来的数据转化为int类型
        choices=[(1,'济南'),(2,'青岛'),(3,'商河')],
        initial=2 #默认显示第二个,可以在函数里面设置类(【c】)
    )
View Code

1.6MultipleChoiceField(ChoiceField)//多选select,其余与1.5相同, 还有TypedMultipleChoiceField(MultipleChoiceField)

 hobby=fields.MultipleChoiceField(
        choices=[(1,'LoL'),(2,'王者荣耀'),(3,'问道'),(4,'qq飞车')],
        initial=[1,2,3]
 ) 
View Code

1.7ComboField(Field) //使用多个验证

 fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
View Code

其余内置字段

loatField(IntegerField)
    ...
 
DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度
 
BaseTemporalField(Field)
    input_formats=None          时间格式化   
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 
DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...
 
RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
 
EmailField(CharField)      
    ...
 
FileField(Field)
    allow_empty_file=False     是否允许空文件
 
ImageField(FileField)      
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)
 
URLField(Field)
    ...
 
 
BooleanField(Field)  
    ...
 
NullBooleanField(BooleanField)
    ...
 
ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示
 
 
ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选
     
ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField
 
 
     
TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值
 
MultipleChoiceField(ChoiceField)
    ...
 
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值
 
ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
 
SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
 
FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''
 
GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
 
SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...
 
UUIDField(CharField)           uuid类型
    ...
View Code

常用选择插件

//# 单选slect
    select = fields.CharField(
        initial=2,
        widget=widgets.Select(choices=[(1, 'LoL'), (2, '王者荣耀'), (3, '问道'), (4, 'qq飞车')])

    )
    select2 = fields.ChoiceField(
        choices=[(1, '济南'), (2, '青岛'), (3, '商河')],
        initial=2,
        widget=widgets.Select()

    )
  // 多选select
  hobby2 = fields.MultipleChoiceField(
    choices=[(1, 'LoL'), (2, '王者荣耀'), (3, '问道'), (4, 'qq飞车')],
    widget=widgets.SelectMultiple(attrs={'class':'c1'})

)



   //# 多选checkbox,值为列表

   xdb = fields.MultipleChoiceField( initial=[], choices=((1, '上海'), (2, '北京'),),
   widget=widgets.CheckboxSelectMultiple )

   //#单选checkbocx xdb2=fields.CharField( widget=widgets.CheckboxInput() )



    //# 单radio,值为字符串
    usera = fields.ChoiceField(
        choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.RadioSelect
    )
   // usera2 = fields.CharField(
        initial=2,
        widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
    )

 

在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。

方式一 推荐用法:

from django.shortcuts import render,redirect
from app01 import models
# Create your views here.
from django import  forms
from django.forms import  fields
from django.forms import widgets
class LoveFrom(forms.Form):
    price=fields.IntegerField()
    user_id =fields.IntegerField(

        # widget=widgets.Select(choices=[(0,'alex'),(1,'佩奇'),(3,'小红')])//默认显示下面是数据库显示方法
        # widget=widgets.Select(choices=models.UserInfo.objects.all().values_list('id','username'))
        #//因为下面写了init方法 所以每次都会执行下面的sql语句,这一句就多余了
    )
    def __init__(self, *args,**kwargs):
        super(LoveFrom,self).__init__()
        self.fields['user_id'].widget.choices=models.UserInfo.objects.all().values_list('id','username')
View Code

方式二 使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现,不推荐

class LoveFrom(forms.Form):
    price=fields.IntegerField()
    from django.forms.models import ModelChoiceField
    user_id2=ModelChoiceField(queryset=models.UserInfo.objects.all())
//这个方法在html显示都是字符,必须在类里面定义一个方法,
View Code

初始化数据

在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。

1 类部分

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
 
class MyForm(Form):
    user = fields.CharField()
 
    city = fields.ChoiceField(
        choices=((1, '上海'), (2, '北京'),),
        widget=widgets.Select
    )
//也可以用默认值显示
View Code

2 Views

from django.shortcuts import render, redirect
from .forms import MyForm
 
 
def index(request):
    if request.method == "GET":
        values = {'user': 'root', 'city': 2}
        obj = MyForm(values)
        //obj = TestFrom({'city':3,'hobby':[1,2,3]})
    
 
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        return redirect('http://www.google.com')
    else:
        return redirect('http://www.google.com')        
View Code

3 html

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <p>{{ form.user }} {{ form.user.errors }}</p>
    <p>{{ form.city }} {{ form.city.errors }}</p>
 
    <input type="submit"/>
</form>
View Code

自定义验证规则

方式一:

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
    user = fields.CharField(
        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
    ) //定义两了个验证规则, 第一个是正则表达式,第二个是错误信息

方式二

RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
    user = fieldsRegexField(r'^[0-9]+$',
    error_messages={'invalid': '...'} //错误信息
   
)
View Code

 方式三Form扩展(钩子函数)

如果对username做扩展   先做正则表达式判断然  后自定义方法验证:也就是clean_xx,   称为钩子函数

class AjaxFrom(forms.Form):
    username=fields.CharField(
        required=True,
        max_length=10,
        min_length=2
    )

    user_id =fields.IntegerField(
 widget=widgets.Select(choices=[(0,'alex'),(1,'佩奇'),(3,'小红')])
        # widget=widgets.Select(choices=models.UserInfo.objects.all().values_list('id','username'))
    )
    //def clean_username(self):  定义clean_+字段名
    //   v=self.cleaned_data['username'] 先拿username
    //   if UserInfo.objects.filter(username=v).count()://如果数量不是0
    //    raise ValidationError('用户名已存在') 抛出异常

    //    return v //如果是0返回

联合唯一

    def clean_username(self):
        v = self.cleaned_data['username']
        if models.UserInfo.objects.filter(username=v).count():
            # 整体错了
            # 自己详细错误信息
            raise ValidationError('用户名已存在')
        return v
    def clean_user_id(self):
        return self.cleaned_data['user_id']

    def clean(self):
        value_dict = self.cleaned_data
        v1 = value_dict.get('username')
        v2 = value_dict.get('user_id')
        if v1 == 'root' and v2==1:
            raise ValidationError('整体错误信息')
        return self.cleaned_data
View Code

 验证码

1 准备好 check_code.py 和 Monaco.ttf

2

from utils.check_code import create_validate_code
from io import BytesIO

def check_code(request):
    """
    验证码
    :param request:
    :return:
    """

    stream = BytesIO() //内存里面打开一个文件
    img,code = create_validate_code() //获取一个img对象,一个code字符串

    img.save(stream,'Png') //生成图片
    request.session['CheckCode'] = code //设置来访问游览器的session 里面的随机字符串为K 值为一个字典 把session['CheckCode'] = code 
    return HttpResponse(stream.getvalue()) 返回

 

 

4

#!/usr/bin/env python
# -*- coding:utf-8 -*-
//创建base.py文件 建一个类
class BaseForm(object):
    def __init__(self, request, *args, **kwargs):
        self.request = request
        super(BaseForm, self).__init__(*args, **kwargs)

5

from .base import BaseForm

class LoginFrom(BaseForm ,djan_froms.Form,):
    # //创建一个myform类,继承 forms.Form


    code = fields.CharField(
        error_messages={
            'required':'请输入验证码'
        }
    )

    def clean_code(self):
        v = self.cleaned_data['code'].upper()
        a = self.request.session.get('CheckCode').upper()
        print(v,a)
        if v != a:
            raise ValidationError('验证码错误')
//把类传进来, 函数里面需要传requst参数
//self.request.session.get('CheckCode').upper() 获取session里面设置的值
// 定义一个钩子函数,如果不相等抛出错误信息

6

        <div class="row">
            <div class="col-xs-7">
                <input type="password" class="form-control" name="code" placeholder="请输入验证码">
            </div>
            <div class="col-xs-5">
                <img src="/creat_code.html" onclick="change_code(this)">
            </div>
            <div> {{ obj.code.errors.0 }} </div>
        </div>


        <input type="submit" class="btn btn-default">
    </form>
</div>
<script>
    function change_code(self) {

        self.src = self.src + "?"

    }
</script>
//定义好验证码, 绑定函数,执行, 点击自动切换验证码, 等于src再次发了一个请求
html部分

 

 

   

 

posted @ 2018-12-24 21:17  new边城  阅读(239)  评论(0)    收藏  举报