form表单使用(博客系统的登陆验证,注册)

先从小的实例来看form的用法

登陆验证实例,来看form的常规用法

1. forms.py

 1 # 用于登陆验证验证
 2 from django.core.validators import RegexValidator 支持正则
 3 # 登陆验证手动触发错误对象
 4 from django.core.exceptions import ValidationError    
 5 
 6 # 登陆规则
 7 class loginform(Form):
 8     name = fields.CharField(
 9         required=True,
10         min_length=3,
11         max_length=18,
12         error_messages={
13             'required':'用户不能为空',
14             'min_length':'用户长度不能小于3',
15             'max_length':'用户长度不能大于18',
16         }
17     )
18     pwd = fields.CharField(
19         required=True,
20         min_length=3,
21         max_length=18,
22         error_messages={
23             'required': '用户不能为空',
24             'min_length': '用户长度不能小于3',
25             'max_length': '用户长度不能大于18',
26             'invalid':'密码格式错误',    #自定义错误,优先级高
27         },validators=[RegexValidator('\d+','只能是数字',code)] #只能是数字也是报错信息,不过优先级低,也就是说如果用户输入非数字,那么提示invalid错误,如果invalid没有,那么报‘只能是数字’错误,code就是给invalid重新命名而已,没有什么用处,可以不写)
28 29 
30     # from扩展,可以直接在里面进行数据库操作,场景注册,局部钩子,博客系统注册,详细介绍了用法,见下文#######
31     def clean_name(self):
32         # 验证可以直接写在这里,进行验证,返回可以是任意类型,重新赋值给clean_date里面的user
33         user = self.cleaned_data['name']
34         is_exsit = models.UserInfo.objects.filter(name=user).count()
35         if not is_exsit:
36             raise ValidationError('用户名不存在')
37         return user
38 
39     def clean_pwd(self):
40         # 这里可以匹配数据库其他校验,返回可以是任意类型,重新赋值给clean_date里面的pwd
41         return True

 

2. views.py

 1 def login(request):
 2     if request.method=='GET':
 3         form = loginform()
 4         return render(request,'login.html',{'form':form})
 5     elif request.method=='POST':
 6         form = loginform(request.POST)  # 前端提交数据给form
 7         # 规则验证
 8         if form.is_valid():
 9             # 数据库验证
10             print('name',form.cleaned_data['name'])
11             user_obj = models.UserInfo.objects.filter(**form.cleaned_data).first()
12             if not user_obj:
13                 form.add_error('pwd',ValidationError('用户名或者密码错误')) #当你符合格式,但是数据库没有的时候就会报错,跟局部钩子触发错误是一样的
14                 return render(request,'login.html',{'form':form})
15             else:
16                 print(form.cleaned_data['name'])
17                 work_boj = models.Workers.objects.filter(utow__name=form.cleaned_data['name'], utow__pwd=form.cleaned_data['pwd']).first()
18                 work = work_boj.workname
19                 request.session[settings.USEROBJ] = {'username': user_obj.name, 'work': work}
20                 return redirect('/index/')
21         else:
22             return render(request,'login.html',{'form':form})
23     else:
24         return HttpResponse('访问请求非get,post')

 

3. login.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1">
 7     <title>Title</title>
 8 </head>
 9 <body>
10     <form method="POST">
11         {% csrf_token %}
12             <p>{{ form.username }} {{ form.errors.username.0 }} </p>
13             <p>{{ form.password }} {{ form.errors.password.0 }} </p>
14         <input type="submit" value="提交" />
15     </form>
16 </body>
17 </html>

 

通过问卷的创建修改来看form的高级用法forms.fields.ChoiceField

主要了解下 forms.fields.ChoiceField(choices=[(1,'a'),(2,'b')]),和初始化数据

models.py

 1 class UserInfo(models.Model):
 2     """
 3     员工表
 4     """
 5     name = models.CharField(max_length=32)
 6 
 7     def __str__(self):
 8         return self.name
 9 
10 class ClassInfo(models.Model):
11     """
12     班级表
13     """
14     name = models.CharField(max_length=32)
15     def __str__(self):
16         return self.name
17 
18 class Questionnaire(models.Model):  # 问卷: 班级 :创建者
19     """
20     问卷表
21 
22     """
23     title = models.CharField(max_length=64)
24     cls = models.ForeignKey(to=ClassInfo)
25     creator = models.ForeignKey(to=UserInfo)
26 
27     def __str__(self):
28         return self.title

 

1. forms.py

 1 from django import forms
 2 from django.forms import widgets  # 插件,可以插入些样式
 3 from django.core.exceptions import ValidationError # 手动触发错误
 4 from django.core.validators import RegexValidator # 支持正则
 5 
 6 from app01 import models
 7 
 8 from django.forms.models import ModelChoiceField # 下拉框实时刷新第二种方法
 9 
10 class questionnaire_form(forms.Form): # 问卷规则
11     title = forms.fields.CharField(required=True,
12                                    error_messages={'required':'名称不能为空','invalid':'格式错误'},
13                                    widget=widgets.TextInput(attrs={'placeholder':'问卷名称',
14                                                                     'class':'form-control questionnaire_title'},))
15 
16     # 其他框使用
17     # password = forms.fields.CharField(required=True, error_messages={'required': '密码不能为空'},
18                                 #widget=widgets.TextInput(attrs={'placeholder': '密码', 'class': 'form-control'}))  # 不能为空
19     # email = forms.fields.EmailField(required=True, error_messages={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'},
20     #                           widget=widgets.PasswordInput(attrs={'placeholder': '邮箱', 'class': 'form-control'}))  # 不能为空,且邮箱格式
21     # text = forms.fields.CharField(required=True,error_messages={'required':'密码不能为空'},
22     #                               widget=widgets.Textarea(attrs={'class':'textatea'}))
23     # cls_list = fields.MultipleChoiceField(choices=[])  # 多选框,传过来的值,是列表
24     # def __init__(self, *args, **kwargs):
25     #     super().__init__(*args, **kwargs)
26     #     self.fields['cls_list'].choices = models.ClassList.objects.values_list('id', 'caption')
27 
28     # 第一种实时刷新,通过重构init方法,不需要models的str方法
29     # cls_id = forms.fields.ChoiceField(choices=[])
30     # creator_id = forms.fields.ChoiceField(choices=[])
31     # def __init__(self,*args,**kwargs):
32     #     super().__init__(*args,**kwargs)
33         # 不需要重启,修改后提交后,再点进来可以保证修改完成
34         # self.fields['cls_id'].choices= models.ClassInfo.objects.all().values_list('id','name')
35         # self.fields['creator_id'].choices = models.UserInfo.objects.all().values_list('id','name')
36     
37     # 第二种实时刷新,需要models里面的str方法,不然下拉框都是对象,访问数据库因为返回的是对象
38     cls_id = ModelChoiceField(queryset=models.ClassInfo.objects.all())
39     creator_id = ModelChoiceField(queryset=models.UserInfo.objects.all())
40 
41 
42     # 局部钩子
43     def clean_title(self): # 针对添加的时候,如果有questionnaire_title,就存在,没有可以正常进行
44         questionnaire_title = models.Questionnaire.objects.filter(title=self.cleaned_data.get('title')) # 前端传来的数据保存在clean_data里
45         if not questionnaire_title:
46             return self.cleaned_data.get('title')
47         else:
48             raise ValidationError('用户名已经存在')   # 触发错误

 

2. views.py

 1 from django.shortcuts import render,HttpResponse,redirect
 2 
 3 # Create your views here.
 4 
 5 from .forms import *
 6 from app01 import models
 7 
 8 def questionnaire_list(request):
 9     '''
10     问卷首页,格式:8000/questionnaire首页,
11     :param request: 
12     :param questionnaire_id: 
13     :return: 
14     '''
15     questionnaire_list = models.Questionnaire.objects.all() # 所有问卷
16     return render(request, "questionnaire_list.html", {'questionnaire_list':questionnaire_list})
17 
18 
19 def add_questionnaire_obj(request,**kwargs):
20     '''
21     添加问卷
22     :param request: 
23     :param kwargs: 
24     :return: 
25     '''
26     if request.method == 'GET':
27         form = questionnaire_form()
28         return render(request, 'add_questionnaire_obj.html',{'form':form})
29     elif request.method == 'POST':
30         form = questionnaire_form(request.POST)
31         print(request.POST)
32         # 校验
33         if form.is_valid():
34             print(form.cleaned_data)
35             # 下拉框第二种实时更新方法,因为前端是queryset对象,所以需要把cleand_data数据重新更改一下
36             # form.cleaned_data['creator_id'] = form.cleaned_data['creator_id'].id
37             # form.cleaned_data['cls_id'] = form.cleaned_data['cls_id'].id
38             models.Questionnaire.objects.create(**form.cleaned_data)
39             return redirect('/questionnaire/')
40         else:
41             return render(request, 'add_questionnaire_obj.html', {'form': form})
42 
43 
44 
45 def edit_questionnaire_obj(request,**kwargs):
46     '''
47     问卷对象,格式:8000/questionnaire/questionnaire_id,选中问卷编辑
48     :param request: 
49     :param kwargs: 
50     :return: 
51     '''
52     questionnaire_id = kwargs.get('questionnaire_id')  # 得到需要编辑的问卷的ID
53     if request.method == 'GET':
54         questionnaire_obj = models.Questionnaire.objects.filter(id=questionnaire_id).first()  # 通过ID找到问卷对象
55         # form的实例化,initial初始化,适用于初始默认的值,
56         # form = questionnaire_form(),没有数据,只是可以在前端渲染标签,需要在FORM里面执行,例如TEXTIINPUT
57         # form = questionnaire_form(data=request.POST),有数据,并且到FORM里面进行验证
58         # 初始化的值,initial={'对象字段名称':,'对象字段,如果是关联字段加上ID,也就是数据库字段是什么,就是什么':}
59         # 初始化的字段名称最好跟MODELS的一样,FORM验证最好也是一样,前端也是一样,这样确保可以正常  ###########  注意
60         form = questionnaire_form(initial={"title":questionnaire_obj.title, "cls_id":questionnaire_obj.cls_id,"creator_id":questionnaire_obj.creator_id}) # 默认值
61         return render(request, "edit_questionnaire_obj.html", {'form': form})
62     if request.method == 'POST':
63         form =questionnaire_form(data=request.POST)
64         if form.is_valid():
65             print(form.cleaned_data)
66             print(form.errors)
67             models.Questionnaire.objects.filter(id=questionnaire_id).update(**form.cleaned_data)
68             return redirect('/questionnaire/')
69         else:
70             return render(request, 'edit_questionnaire_obj.html', {'form': form})

 

 

3. questionnaire_obj.html 

1     <form action="" method="post">
2         {% csrf_token %}
3         <p>问卷调查名称:{{ form.title }}</p>
4         <p>选择班级:{{ form.cls_id }}</p>
5         <p>选择创建者:{{ form.creator_id }}</p>
6         <input type="submit" value="提交">
7     </form>

 

博客系统注册,读完肯定清晰明了,注意这里面有全局钩子的用法,

针对from.error下的__all__

models结构如下

 1 class UserInfo(AbstractUser):
 2     """
 3     用户信息
 4     """
 5     nid = models.AutoField(primary_key=True)
 6     nickname = models.CharField(verbose_name='昵称', max_length=32)
 7     telephone = models.CharField(max_length=11, null=True, unique=True)
 8     avatar = models.FileField(upload_to='avatar/',default="/avatar/default.png")
 9     create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
10     blog = models.OneToOneField(to='Blog', to_field='nid',null=True)
11 
12     def __str__(self):
13         return self.username

 

forms

 1 from django import forms
 2 from django.forms import widgets
 3 
 4 from . models import UserInfo
 5 from django.core.exceptions import NON_FIELD_ERRORS,ValidationError  #  手动触发错误
 6 
 7 
 8 
 9 class RegForm(forms.Form): # 子类
10     # widget 默认情况下,CharField 具有一个TextInput 在HTML 中生成一个<input type="text">
11     # attrs 可以对input标签添加属性
12     def __init__(self,request,*args,**kwargs): # 派生方法
13         super().__init__(*args,**kwargs)
14         self.request = request # 派生属性
15     user = forms.CharField(min_length=5,max_length=12,required=True,  # 规则
16                            error_messages={'min_length':'最小长度5','max_length':'最大长度12','required':'不能为空'}, # 错误信息
17                            widget = widgets.TextInput(attrs={'class':'form-control','placeholder':'username'})) # 生成标签,标签属性
18 
19     pwd = forms.CharField(required=True,error_messages={'required':'不能为空'},widget = widgets.PasswordInput(attrs={'class':'form-control','placeholder':'password'}))
20 
21     repeat_pwd = forms.CharField(required=True,error_messages={'required':'不能为空'},widget = widgets.PasswordInput(attrs={'class':'form-control','placeholder':'repeat_password'}))
22 
23     email = forms.EmailField(required=True,error_messages={'invalid':'格式错误','required':'不能为空'},
24                              # 生成一个EmailInput <input type="input">
25                              widget = widgets.EmailInput(attrs={'class':'form-control','placeholder':'email','required':'不能为空'}))
26 
27     valid_code = forms.CharField(required=True,error_messages={'required':'不能为空'},widget = widgets.TextInput(attrs={'class':'form-control','placeholder':'valid_code'}))
28 
29     # 局部钩子,针对user的验证
30     def clean_user(self):
31         user = UserInfo.objects.filter(username=self.cleaned_data.get('user'))
32         if not user:
33             return self.cleaned_data.get('user')
34         else:
35             raise ValidationError('用户名已经存在')
36 
37     # 局部钩子,针对pwd的验证
38     def clean_pwd(self):
39         pwd = self.cleaned_data.get('pwd')
40         if pwd.isdigit() or pwd.isalpha():
41             raise ValidationError('不能是纯数字或者纯字母')
42         else:
43             return pwd
44 
45     # 局部钩子,针对验证码的验证
46     def clean_valid_code(self):
47         val = self.cleaned_data.get('valid_code')
48         if val.upper() == self.request.session.get('valid_code_str').upper():
49             return val
50         else:
51             raise ValidationError('验证码错误')
52 
53     # 全局钩子,针对全局上的验证,注意,先走局部后走全局
54     def clean(self):
55         if self.cleaned_data.get('pwd'):
56             if self.cleaned_data.get('pwd') == self.cleaned_data.get('repeat_pwd'):
57                 return self.cleaned_data
58             else:
59                 raise ValidationError('俩次密码不一致')
60 
61     # 正确信息保存在,clean.data
62     # 错误信息保存在,clean.error

 

1. urls

1 urlpatterns = [
2     url(r'^admin/', admin.site.urls),
3     url(r'^login/', views.login_in),
4     url(r'^register/', views.register),
5 ]

 

2. views

 1 from .forms import *
 2 def register(request):
 3     if request.is_ajax():
 4         # 通过from表单验证
 5         print(request.POST)
 6         regForm = RegForm(request,request.POST)
 7         regResponse = {'user':None,'errors':None}
 8         if regForm.is_valid():
 9             # 通过验证,可以注册
10             data = regForm.cleaned_data  # 合法的表单数据,是以字典形式保存
11             user = data.get('user')
12             pwd = data.get('pwd')
13             email = data.get('email')
14             avatar_img = request.FILES.get('valid_img') #获取的文件对象
15             print(avatar_img)
16             print(type(avatar_img))
17             # user_obj = UserInfo.objects.filter(nid=2).update(avatar=avatar_img)
18             user_obj = UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar=avatar_img)
19             regResponse['user'] = user_obj.username
20         else:
21             regResponse['errors'] = regForm.errors   # regForm.errors 保存所有错误信息,包括__all__全局钩子错误
22         return JsonResponse(regResponse)
23 
24     regForm = RegForm(request) # 前端渲染,虽然没有数据,但是会渲染出标签来
25     return render(request,'register.html',{'regForm':regForm})

 

3. reg.html

 1 <div class="container">
 2     <div class="row">
 3         <div class="col-md-6 col-md-offset-3">
 4             <form>
 5                 {% csrf_token %}
 6                 <div class="form-group">
 7                     <label for="user">用户名:</label>
 8 {#                    <input type="text" class="form-control" id="user" placeholder="User">#}
 9                     {{ regForm.user }} <span></span>
10                 </div>
11 
12                 <div class="form-group">
13                     <label for="pwd">密码:</label>
14 {#                    <input type="password" class="form-control" id="pwd" placeholder="Password">#}
15                     {{ regForm.pwd }} <span></span>
16                 </div>
17 
18                 <div class="form-group">
19                     <label for="repeat_pwd">确认密码:</label>
20 {#                    <input type="password" class="form-control" id="repeat_pwd" placeholder="Repeat Password">#}
21                     {{ regForm.repeat_pwd }} <span></span>
22                 </div>
23 
24                 <div class="form-group">
25                     <label for="email">邮箱:</label>
26 {#                    <input type="email" class="form-control" id="email" placeholder="Email">#}
27                     {{ regForm.email }} <span></span>
28                 </div>
29                 <div class="row">
30                     <div class="col-md-6">
31                         <input type="button" value="confirm register" class="btn btn-primary regBtn">
32                     </div>
33                 </div>
34 
35             </form>
36 
37         </div>
38     </div>
39 </div>
40 
41 <script>
42  {#    AJAX提交注册表单,注册用户 #}
43     $(".regBtn").click(function () {
44 
45         var $formData = new FormData();
46 
47         $formData.append('user',$('#id_user').val());
48         $formData.append('pwd',$('#id_pwd').val());
49         $formData.append('repeat_pwd',$('#id_repeat_pwd').val());
50         $formData.append('email',$('#id_email').val());
51         $formData.append('valid_code',$('#id_valid_code').val());
52         var file = $('#avatar_file')[0].files[0];
53         $formData.append('valid_img',file);
54         $formData.append('csrfmiddlewaretoken',$("[name='csrfmiddlewaretoken']").val());
55 
56         $.ajax({
57             url: "/register/",
58             type: "POST",
59             data: $formData,
60             processData:false,   // 不做转码或预处理
61             contentType:false,   // 文件类型不做处理
62             success: function (data) {
63                 if (data.user) {
64                     location.href = '/login/'
65                 }
66                 else {
67                     $('span').html('');
68                     $(".form-group").removeClass("has-error");
69                     console.log(data.errors);
70 
71                     $.each(data.errors,function (i,j) {
72                         $("#id_" + i).next().addClass('pull-right').css('color', 'red').html(j[0]).parent().addClass('has-error');
73                         if(i == "__all__") {
74                             $("#id_repeat_pwd").next().addClass("pull-right").css("color", "red").html(j[0]).parent().addClass("has-error");
75                             $("#id_pwd").parent().addClass("has-error");
76                         }
77                     })
78                 }
79             }
80         })
81     })
82 </script>

 

posted @ 2017-12-31 15:03  liqianlong  阅读(1561)  评论(0编辑  收藏  举报