• Django——form组件is_valid校验机制


    #先来归纳一下整个流程
    #(1)首先is_valid()起手,看seld.errors中是否值,只要有值就是flase
    #(2)接着分析errors.里面判断_errors是都为空,如果为空返回self.full_clean(),否则返回self._errors
    #(3)现在就要看full_clean(),是何方神圣了,里面设置_errors和cleaned_data这两个字典,一个存错误字段,一个存储正确字段。
    #(4)在full_clean最后有一句self._clean_fields(),表示校验字段
    #(5)在_clean_fields函数中开始循环校验每个字段,真正校验字段的是field.clean(value),怎么校验的不管
    #(6)在_clean_fields中可以看到,会将字段分别添加到_errors和cleaned_data这两个字典中
    #(7)结尾部分还设置了钩子,找clean_XX形式的,有就执行。执行错误信息也会添加到_errors中
    #(8)整个校验过程完成
    #下面分析form组件中is_valid校验的流程
    #在分析过程中重点关注_erroes和clean_data这两个字典
    def login(request):
        if request.method == "POST":
            form_obj = LoginForm(request.POST)
            if form_obj.is_valid():
                #如果检验全部通过
                print(form_obj.clean_data) #这里全部都没问题
                return HttpResponse("你好,欢迎回来!")
            else:
                #print(form_obj.clean_data)
                #print(form_obj.errors)
                return render(request, "login.html", {"form_obj": form_obj,)
    
        form_obj = LoginForm()
        return render(request, "login.html", {"form_obj": form_obj})
    个人代码实例
    def register(request):
        if request.is_ajax():
            print('request.POST',request.POST)
            form = UserForm(request.POST)  # 把值传入form表单中
            print('form', form)
    
            response = {"user": None, "msg": None}
            if form.is_valid():
                response["user"] = form.cleaned_data.get("user")
    
                # 生成一条用户纪录
                user = form.cleaned_data.get("user")
                print("user", user)
                pwd = form.cleaned_data.get("pwd")
                email = form.cleaned_data.get("email")
                avatar_obj = request.FILES.get("avatar")
    
                extra = {}
                if avatar_obj:
                    extra["avatar"] = avatar_obj
    
                UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
                print('UserInfo',UserInfo)
    
            else:
                print('form.cleaned_data',form.cleaned_data)
                print('form.errors',form.errors)
                response["msg"] = form.errors
                print('response', response)
    
            return JsonResponse(response)
    
        form = UserForm()
        print('form = UserFrom', form)
        return render(request, "register.html", {"form": form})

    个人视图

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
        <script src="/static/js/jquery-3.2.1.min.js"></script>
        <style>
            #avatar_img {
                margin-left: 20px;
            }
    
            #avatar {
                display: none;
            }
    
            .error {
                color: red;
            }
        </style>
    
    </head>
    <body>
    <h3>注册页面</h3>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-lg-offset-3">
    
                <form id="form">
                    {% csrf_token %}
    
                    {% for field in form %}
                        <div class="form-group">
                            <label for="{{ field.auto_id }}">{{ field.label }}</label>
                            {{ field }} <span class="error pull-right"></span>
                        </div>
                    {% endfor %}
    
                    <div class="form-group">
                        <label for="avatar">
                            头像
                            <img id="avatar_img" width="60" height="60" src="/static/blog/img/default.png" alt="">
                        </label>
                        <input type="file" id="avatar" name="avatar">
                    </div>
    
                    <input type="button" class="btn btn-default reg_btn" value="submit"><span class="error"></span>
    
                </form>
    
            </div>
        </div>
    </div>
    
    
    <script>
        // 头像预览
        $("#avatar").change(function () {
    
            // 获取用户选中的文件对象
            var file_obj = $(this)[0].files[0];
            // 获取文件对象的路径
            var reader = new FileReader();
            reader.readAsDataURL(file_obj);
            // 修改img的src属性 ,src=文件对象的路径
            reader.onload = function () {
                $("#avatar_img").attr("src", reader.result)
            };
    
        });
    
        // 基于Ajax提交数据
    
        $(".reg_btn").click(function () {
            //console.log($("#form").serializeArray());
            var formdata = new FormData();
    
            var request_data = $("#form").serializeArray();
            console.log(request_data);
            $.each(request_data, function (index, data) {
                formdata.append(data.name, data.value)
            });
    
            formdata.append("avatar", $("#avatar")[0].files[0]);
            console.log('formdata',formdata);
            $.ajax({
                url: "",
                type: "post",
                contentType: false,
                processData: false,
                data: formdata,
                success: function (data) {
                    //console.log(data);
    
                    if (data.user) {
                        // 注册成功
                        location.href="/login/"
                    }
                    else { // 注册失败
    
                        //console.log(data.msg)
                        // 清空错误信息
                        $("span.error").html("");
                        $(".form-group").removeClass("has-error");
    
                        // 展此次提交的错误信息!
                        $.each(data.msg, function (field, error_list) {
                            console.log(field, error_list);
                            if (field=="__all__"){
                                $("#id_re_pwd").next().html(error_list[0]).parent().addClass("has-error");
                            }
                            $("#id_" + field).next().html(error_list[0]);
                            $("#id_" + field).parent().addClass("has-error");
    
    
                        })
    
                    }
                }
            })
    
        })
    
    
    </script>
    
    </body>
    </html>

    钩子讲理(非自己)

    #钩子代码实例
    def clean_user(self):
        val1 = self.cleaned_data.get("user")
        #从正确的字段字典中取值
        #如果这个字符串全部都是由数组组成
        if not val1.isdigit():
            return val1
        else:
            # 注意这个报错信息已经确定了
            raise ValidationError("用户名不能全部是数字组成")
            #在校验的循环中except ValidationError as e:,捕捉的就是这个异常
            #所以能将错误信息添加到_errors中
    
    
    
    #代码分析部分
    def is_valid(self):
        """
        Returns True if the form has no errors. Otherwise, False. If errors are
        being ignored, returns False.
        如果表单没有错误,则返回true。否则为假。如果错误是被忽略,返回false。
        """
        return self.is_bound and not self.errors
        #is_bound默认有值
        #只要self.errors中有一个值,not True = false,返回的就是false
    
    
    def errors(self):
        """
        Returns an ErrorDict for the data provided for the form
        返回一个ErrorDict在form表单存在的前提下
        """
        if self._errors is None:
            self.full_clean()
        return self._errors
    
    
    def full_clean(self):
        """
        Cleans all of self.data and populates self._errors and self.cleaned_data.
        清除所有的self.data和本地的self._errors和selif.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):
        #每个form组件实例化的过程中都会创建一个fields。fields实质上是一个字典。
        #储存着类似{"user":"user规则","pwd":"pwd的规则对象"}
        for name, field in self.fields.items():
            #name是你调用的一个个规则字段,field是调用字段的规则
            #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.
            
            value_from_datadict()从数据字典中获取数据。
            每个部件类型知道如何找回自己的数据,因为有些部件拆分数据在几个HTML字段。
            """
            #现在假设第一个字段是user
            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)
                    #filed是一个对象,field.clean才是真正的规则校验
                else:
                    #你不是文件的时候怎么校验
                    #实际中也是走的这一部,value是你输入的字段值
                    #如果没有问题,那么原样返回
                    value = field.clean(value)
                    #如果一旦出现问题,那么就会走except中的代码
                self.cleaned_data[name] = value
    
                if hasattr(self, 'clean_%s' % name):  #这里找是否有clean_XX这个名字存在
                    value = getattr(self, 'clean_%s' % name)()  #如果有执行这个函数
                    self.cleaned_data[name] = value  #而在钩子中必须报错的返回值是确定的
                    #如果上面有问题,就又把错误添加到了_error中
                    #上面这三行代码是我们能添加钩子的原因,而且规定了钩子名的格式
    
                    #如果这个值是正确的话,就会给这个字典添加一个键值对
                    #刚才在full_clean中self.cleaned_data = {}已经初始化了。
                    #{”pws“:123}
            except ValidationError as e:
                self.add_error(name, e)
                #如果出现错误,就会给_error这个字典添加一个键值对
                #至于add_error这个函数如何添加这个键值对的,我们先不管
                #键就是name,值就是错误信息e
                #在full_clean中已经初始化self._errors = ErrorDict()
                #假设现在user有问题,那么_error就是这样{”user“:e}
  • 相关阅读:
    EasyUI的DataGrid 打印导出
    js 验证各种格式类型的正则表达式
    双机热备方案
    使用 IDEA 创建 Maven Web 项目 (异常) Disconnected from the target VM, address: '127.0.0.1:59770', transport: 'socket'
    MySQL 常用函数
    使用 IDEA 创建 Maven Web 项目 (四) 让 WEB 应用跑起来
    使用 IDEA 创建 Maven Web 项目 (二) 搭建 WEB 项目框架
    使用 IDEA 创建 Maven Web 项目 (三) 编写一个简单的 WEB 应用
    Android 开发环境 —— Eclipse 启动时报错:Error when loading the SDK
    使用 EasyUI 创建左侧导航菜单
  • 原文地址:https://www.cnblogs.com/cjj-zyj/p/9968230.html
Copyright © 2020-2023  润新知