zoukankan      html  css  js  c++  java
  • python测试开发django-114.ModelForm中局部钩子(clean_)和全局钩子校验

    前言

    在实际开发中,不仅仅是对输入框字符的格式校验,比如注册功能,注册账号还得校验数据库是否已经有账号被注册过了。
    有些场景不仅仅是对单个输入框的字符校验,比如修改密码的时候,会涉及2个输入框的数据格式校验,像这些复杂的场景校验需用到校验钩子来实现。
    校验form表单数据合法性,is_valid()方法调用顺序:

    • 1.字段规则校验,字符长度,是否必填等基本校验
    • 2.validators校验(RegexValidator校验器或自定义校验函数)
    • 3.局部钩子(类中定义的以clean_字段名命名的函数,校验正常必须返回该字段的值self.cleaned_data.get('name'))
    • 4.全局钩子(类中定义的函数名clean,校验正常必须返回该对象的校验结果值return self.cleaned_data)
    • 5.每一步通过校验单结果都以字典形式保存在类对象的cleaned_data属性中

    ModelForm模型表单

    局部钩子命名规则为clean_字段名称,如:clean_city,clean_years。
    super() 重写__init__,可以批量更新class属性。

    # 作者-上海悠悠 QQ交流群:717225969
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    
    class SubmitPageForm(forms.ModelForm):
    
        class Meta:
            model = Submit
            # fields = "__all__"  #全部字段
            fields = ["city", "years", "details"]
            widgets = {
                "city": widgets.TextInput(attrs={
                    "placeholder": "输入城市:北京/上海/深圳"
                }),
                "years": widgets.TextInput(attrs={
                    "placeholder": "输入年限"}),
                "details": widgets.TextInput(attrs={
                    "placeholder": "输入详情"}),
    
            }
            labels = {
                "city": "城 市",
                "years": "年 限",
                "details": "详 情",
            }
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            # 批量更新class属性
            for field in self.fields.values():
                field.widget.attrs.update({'class': 'form-control'})
    
        def clean_city(self):
            """局部钩子判断城市必须是北京/上海/深圳其中一个"""
            city_val = self.cleaned_data.get('city', '')
            if city_val in ["北京", "上海", "深圳"]:
                return city_val
            else:
                self.add_error("password", ValidationError('城市只能选:北京/上海/深圳'))                       
                # raise forms.ValidationError('城市只能选:北京/上海/深圳')
    
    

    定义视图

    # 作者-上海悠悠 QQ交流群:717225969
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    
    class SubmitView(View):
    
        def get(self, request):
            form_obj = SubmitPageForm
            return render(request, "submit.html", locals())
    
        def post(self, request):
            form_obj = SubmitPageForm(request.POST)
            if form_obj.is_valid():
                # data = form_obj.cleaned_data()
                form_obj.save()
                msg = "保存成功"
                return HttpResponseRedirect('/total')
    
            else:
                # 全局钩子自定义错误提示获取
                # print(form_obj.errors.get('__all__'))
                # error_msg = form_obj.errors.get('__all__')
                return render(request, "submit.html", locals())
    
    

    模板内容

    模板内容如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>提交页面</title>
        <meta charset="utf-8">
    	<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    	<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    	<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    </head>
    <body>
    
    <div class="container">
    
       <form role="form" action="" method="POST" id="detail-form" >
        {% csrf_token %}
        {% for field in form_obj %}
            <div class="form-group">
                {{ field.label_tag }}
                {{ field }}
                <div style="color: red"> {{ field.errors }} </div>
    
            </div>
    
        {% endfor %}
        <p>
            <input type="submit" value="提交" >
        </p>
    </form>
    </div>
    </body>
    </html>
    
    

    页面效果

    输入不合法的内容,会显示field.errors内容

    全局钩子

    针对单个字段校验可以用局部钩子实现,如果我们要校验多个字段,比如校验注册的时候输入2次密码一致,可以用全局钩子实现。
    定义全局钩子使用clean方法

    # 作者-上海悠悠 QQ交流群:717225969
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    
    class SubmitPageForm(forms.ModelForm):
    
        class Meta:
            model = Salary
            fields = "__all__"  #全部字段
        # 省略中间代码。。。。。
    
        # 全局钩子
        def clean(self):
            """在通过基础验证的干净数据中get获取字段"""
            pwd1 = self.cleaned_data.get('password')
            pwd2 = self.cleaned_data.get('password2')
            if pwd1 and pwd2:  # 这里判断2个字段都是校验通过
                if pwd1 == pwd2:
                    # 数据没问题,那么原封不动返回即可
                    return self.cleaned_data
                else:
                    # 错误信息储存到 errors {'__all__':[e,]}
                    self.add_error("password", ValidationError('两次密码输入不同'))
                    # raise ValidationError('两次密码输入不同')
            else:
                return self.cleaned_data
    

    前端可以通过fomr_obj.errors.__all__ 获取到内置校验器的全部错误信息

    钩子校验失败

    钩子校验失败的时候,需把异常添加到error类,可以选择2种方式

    # 方式1-raise
    raise ValidationError('两次密码输入不同')
    

    也可以用add_error方法

    # 方式2-add_error
    self.add_error("password", ValidationError('两次密码输入不同'))
    
  • 相关阅读:
    MySQL全文索引应用简明教程
    web前端的春天 or 噩梦
    [DeviceOne开发]-手势动画示例分享
    [DeviceOne开发]-土地销售项目源码分享
    [DeviceOne开发]-do_LinearLayout组件使用技巧
    2016年我们重新思考移动互联网创业的风险, 微信还是APP?
    APP技术演化的路
    ReactNative&weex&DeviceOne对比
    what's deviceone
    APP开放源码第一弹《纳豆》
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/15226059.html
Copyright © 2011-2022 走看看