美文网首页
表单(二)

表单(二)

作者: 费云帆 | 来源:发表于2020-02-12 13:50 被阅读0次

    ● 另一种验证方法---验证器(validator),它的效果和'error_messages'参数类似

    以下是一些常用的验证器:

    <1> MaxValueValidator:验证最大值。

    <2> MinValueValidator:验证最小值。

    <3> MinLengthValidator:验证最小长度。

    <4> MaxLengthValidator:验证最大长度。

    <5> EmailValidator:验证是否是邮箱格式。

    <6> URLValidator:验证是否是URL格式。

    <7> RegexValidator:如果还需要更加复杂的验证,那么我们可以通过正则表达式的验证器:RegexValidator。比如现在要验证手机号码是否合格,那么我们可以通过以下代码实现:

    from django import forms
    from django.core import validators
    
    class MessageBoardForm(forms.Form):
        
        telephone=forms.CharField(validators=[validators.RegexValidator(r'1[345678]\d{9}',
        message='请输入正确格式的手机号码!')])
    

    验证器的基础示例用法:

    # forms
    
    from django import forms
    from django.core import validators # 导入验证器
    
    class MessageBoardForm(forms.Form):
        
        #email=forms.EmailField(label='邮箱',error_messages=dict(required='必须输入email字段',
        #invalid='请输入正确的邮箱地址格式'))
        
        # 通过validators参数指定验证器(list类型,传递message,自定义验证信息)
        email=forms.EmailField(validators=[validators.EmailValidator(message='请输入正确的邮箱地址格式')])
        
    # views
    
    from django.shortcuts import render
    from django.views.generic import View
    from .forms import MessageBoardForm
    from django.http import HttpResponse
    from django.forms.utils import ErrorDict
    
    class FormView(View):
    
        def get(self,request):
            return render(request,'index.html')
    
        def post(self,request):
            form=MessageBoardForm(request.POST)
            if form.is_valid():
                return HttpResponse('数据提交成功!!!')
            else:
                print(form.errors.get_json_data()) # 依旧调用get_json_data()打印错误信息
                return HttpResponse('数据提交失败!')
                
    # index.html
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Message Board</title>
    </head>
    <body>
        <form action="" method="post">
            <label> 邮箱:
                <input type="text" name="email"> # 单纯弄一个文本框测试效果
            </label>
            <input type="submit" value="submit">
        </form>
    </body>
    </html>
    

    访问url,随便输入,终端信息:

    {'email': [{'message': '请输入正确的邮箱格式', 'code': 'invalid'}]}
    

    换成之前的 error_messages 示例,对比一下效果(基本差不多...):

    from django import forms
    from django.core import validators
    
    class MessageBoardForm(forms.Form):
        
        email=forms.EmailField(label='邮箱',error_messages=dict(required='必须输入email字段',
        invalid='请输入正确的邮箱地址格式'))
        
        # email=forms.EmailField(validators=[validators.EmailValidator(
        #     message='请输入正确的邮箱地址格式'
        # )])
    
        '''
        {'email': [{'code': 'invalid', 'message': '请输入正确的邮箱地址格式'}]}
        '''
    

    ● 自定义验证方法---对字段进行验证(单单有验证器是满足不了需求的)

    实现'注册'需求,比如手机号码'telephone'字段值如果已经存在,那就提示'注册失败',终端打印'出错信息'
    显然,这个需求得有数据库的支持了...

    步骤1: 先定义模型(与前端提交的数据进行比对!)

    # front.models
    
    from django.db import models
    
    class User(models.Model):
        # 简单定义两个字段
        username=models.CharField(max_length=100)
        telephone=models.CharField(max_length=11)
        # 下面这句其实已经满足需求了,为了演示,就不这么写
        #telephone=models.CharField(max_length=11,unique=True)
    

    步骤2: 定义'表单'(代码与'model'类似)

    # front.forms
    class RegisterForm(forms.Form):
        username=forms.CharField(max_length=100)
        telephone=forms.CharField(validators=[validators.RegexValidator(
            r'1[345678]\d{9}',message='请输入正确格式的手机号码'
        )])
    

    步骤3: 后端'views',前端模板编写:

    # front.views
    
    class RegisterView(View):
        
        # get加载空表单
        def get(self,request):
            return render(request,'register.html')
    
        def post(self,request):
            form=RegisterForm(request.POST)
            if form.is_valid():
                username=form.cleaned_data.get('username')
                telephone=form.cleaned_data.get('telephone')
                # 把获取的字段,传给模型,插入数据库
                # 这里暂未涉及对'字段'的判断
                User.objects.create(username=username,telephone=telephone)
                return HttpResponse('注册成功!')
            else:
                print(form.errors.get_json_data())
                return HttpResponse('注册失败')
        
    # register.html
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="" method="post"> # 简单定义一个表单
            <table>
                <tr>
                    <td>用户名:</td>
                    <td><input type="text" name="username"></td>
                </tr>
                <tr>
                    <td>手机号码:</td>
                    <td><input type="text" name="telephone"></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="提交"></td>
                </tr>
            </table>
        </form>
    </body>
    </html>
    

    上述步骤完成后,刷新网页看看效果,基本的'注册'功能已经有了'雏形',下来,我们对'telephone'字段'自定义验证':

    # front.forms
    class RegisterForm(forms.Form):
        username=forms.CharField(max_length=100)
        telephone=forms.CharField(validators=[validators.RegexValidator(
            r'1[345678]\d{9}',message='请输入正确格式的手机号码'
        )])
    
        def clean_telephone(self): # clean_field()
            # 获取telephone字段并与数据库对比
            telephone=self.cleaned_data.get('telephone')
            exists=User.objects.filter(telephone=telephone).exists()
            if exists:
                raise forms.ValidationError('{} 已经存在,请变更号码'.format(telephone))
            # clean_field()方法一定要返回field...
            return telephone
    

    刷新网页,插入相同的'telephone'看看效果

    ● 批量自定义字段验证---clean()方法的使用
    现在要在上述示例的基础上,添加'password'字段的验证,如果两次'password'输入不一致,也提示'注册失败',并且的'终端'打印出'验证失败信息'

    class RegisterForm(forms.Form):
        username=forms.CharField(max_length=100)
        telephone=forms.CharField(validators=[validators.RegexValidator(
            r'1[345678]\d{9}',message='请输入正确格式的手机号码'
        )])
        pw1=forms.CharField(max_length=16,min_length=6) # 新增'密码'字段
        pw2=forms.CharField(max_length=16,min_length=6)
    
        def clean_telephone(self):
            ......
            return telephone
        
        # 如果来到了clean()方法,说明之前的每一个字段都验证成功了!
        def clean(self):
            # 查看源码clean()方法返回的是 self.cleaned_data
            clean_data=super().clean() # 调用父类的clean()方法,返回clean_data
            pw1=clean_data.get('pw1')
            pw2=clean_data.get('pw2')
            if pw1 != pw2:
                raise forms.ValidationError(message='两次密码输入不一致!')
            return clean_data # clean()返回的一定是 clean_data
        '''
        # 这里这么写也可以
        def clean(self):
            clean_data=super().clean()
            pw1=self.cleaned_data.get('pw1') # 不使用clean_data,而使用self.cleaned_data,一样的效果
            pw2=self.cleaned_data.get('pw2')
            if pw1!=pw2:
                raise forms.ValidationError('两次密码输入不一致,请重新输入')
            return clean_data
        '''
    

    前端模板修改一下:

    # register.html
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="" method="post">
            <table>
                <tr>
                    <td>用户名:</td>
                    <td><input type="text" name="username"></td>
                </tr>
                <tr>
                    <td>手机号码:</td>
                    <td><input type="text" name="telephone"></td>
                </tr>
                <tr>
                    <td>密码:</td> # 新增passwore文本框,注意type='password'类型
                    <td><input type="password" name="pw1"></td>
                </tr>
                <tr>
                    <td>重复密码:</td>
                    <td><input type="password" name="pw2"></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="提交"></td>
                </tr>
            </table>
        </form>
    </body>
    </html>
    

    刷新网页,看看'密码不一致'效果

    • 需求变更为'用户名'或'手机号码'存在,就提示注册失败,并在终端输出'错误信息',我们使用clean()方法[处理多个字段]一下子搞定[不再定义'clean_field()'对'单独字段'进行处理]

    from django import forms
    from django.core import validators●
    from .models import Register
    from django.db.models import Q
    
    class RegiterForm(forms.Form):
    
        username=forms.CharField(max_length=20)
        telephone=forms.CharField(validators=[validators.RegexValidator(r'1[345678]\d{9}',
        message='请输入正确格式的手机号码!')])
        password1=forms.CharField(max_length=16,min_length=6)
        password2=forms.CharField(max_length=16,min_length=6)
    
        '''def clean_telephone(self):
            telephone=self.cleaned_data.get('telephone')
            exists=Register.objects.filter(telephone=telephone).exists()
            if exists:
                raise forms.ValidationError(message='手机号码已经存在,请变更手机号码!')
            return telephone
    
        def clean_username(self):
            username=self.cleaned_data.get('username')
            exists=Register.objects.filter(username=username).exists()
            if exists:
                raise forms.ValidationError(message='用户名已经存在,请变更注册名')
            return username'''
    
        def clean(self):
    
            clean_data=super().clean()
            password1=clean_data.get('password1')
            password2=clean_data.get('password2')
            username=clean_data.get('username')
            telephone=clean_data.get('telephone')
    
            if password1 != password2:
                raise forms.ValidationError(message='密码输入不一致,请重新输入!')
    
            exists = Register.objects.filter(Q(telephone=telephone) | Q(username=username)).exists()
            if exists:
                raise forms.ValidationError(message='用户名或手机号码已经存在,请变更用户名或手机号码!')
            
            return clean_data
    

    什么时候使用clean_field(),什么时候使用clean(),看情况而定了...

    ● 处理'错误信息',使其显示更加友好,之前的错误信息是这样的:

    dict1={'telephone': [{'code': 'invalid', 'message': '请输入正确格式的手机号码'}], '__all__': [{'code': '', 'message': '两次密码输入不一致!'}]}
    

    我们改进一下,变成下面这样的,显然更为'友好':

    {'telephone': ['请输入正确格式的手机号码'], '__all__': ['两次密码输入不一致!']}
    

    示例:

    # fomrs
    from django import forms
    from django.core import validators
    from .models import User
    
    class RegisterForm(forms.Form):
        username=forms.CharField(max_length=100)
        ......
    
        def clean_telephone(self):
            ......
            return telephone
    
        def clean(self):
            ......
            return clean_data
    
        def get_errors(self):# 自定义get_errors()方法,改进'错误信息'
        
            errors=self.errors.get_json_data() # 调用 get_json_data()方法,获取'信息dict'
            new_errors={} # 定义空dict,把改进后的结果,扔进来
            for key,message_dicts in errors.items():
                messages=[] # 收集字典的'value'值
                for message_dict in message_dicts:
                    message=message_dict['message']
                    messages.append(message)
                new_errors[key]=messages
            return new_errors
    
    # views
    
    class RegisterView(View):
    
        def get(self,request):
            return render(request,'register.html')
    
        def post(self,request):
            ......
            else:
                print(form.get_errors()) # 不再是调用get_json_data()
                return HttpResponse('注册失败')
        '''
        {'__all__': ['两次密码输入不一致!'], 'telephone': ['请输入正确格式的手机号码']}
        '''
    
    

    相关文章

      网友评论

          本文标题:表单(二)

          本文链接:https://www.haomeiwen.com/subject/rujqfhtx.html