zoukankan      html  css  js  c++  java
  • day061 Django之form组件和用户认证组件

    本节内容:

    1、form组件(校验字段的功能)
    2、用户认证组件
    

    一、form组件(校验字段的功能)

    在views.py下创建一个对应该表的类,规定输入字段的规则
    

    1、四条语法

    ef = EmpForm({"name":"shuying", "age":20}) # 实例化一个form对象,传的实参为一个字典,
    #           为你要校验的字段,注意键名要跟类变量的名一致
    
    ef.is_valid() # 检验字段,是否符合规则
    ef.cleaned_data # 拿到干净的数据
    ef.errors  # 拿到错误的信息,样式为字典:{'name': ['This field is required.']}
    
    语法演示
    # 在views.py文件下
    from django import forms # forms组件
    
    class EmpForm(forms.Form): # 通过创建一个类,来限定输入字段规则
        name=forms.CharField(min_length=5)
        age=forms.IntegerField()
    
    # Django控制台查看
    from app01.models import  EmpForm
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    ImportError: cannot import name 'EmpForm'
    
    from app01.views import  EmpForm
    ef=EmpForm({"name":"yuan","age":23}) # 示例一个form对象,传参为一个字典
    ef.is_valid() # 检验字段,是否符合规则
    False
    ef=EmpForm({"name":"yuan123","age":23})
    ef.is_valid()
    True
    
    ef=EmpForm({"name":"yuan123","age":23,"a":1}) # 传参字段多了,没有问题,不影响校验结果,
    ef.is_valid()
    True
    
    ef=EmpForm({"names":"yuan123","age":23,"a":1}) # 校验的传入的实参键值对的键名要和form类使用的类属性的名一致
    ef.is_valid()                                  # 校验只要有一项不符合规则,就报错不通过,类似于事务
    False
    
    ef.cleaned_data  # 获取干净的数据
    {'age': 23}
    
    ef.errors   # 获取错误的数据
    {'name': ['This field is required.']}
    
    Python

    2、作用之校验数据(重点)

    通过创建一个类,该类继承forms.Form类,
    就可以通过其来起到校验数据的作用
    
    class EmpForm(forms.Form):  # 限制字段的条件,校验数据
        name=forms.CharField(min_length=5,label="姓名",error_messages={"required":"该字段不能为空!"})  # 返回对应错误的提示
        age=forms.IntegerField(label="年龄")
        salary=forms.CharField(label="薪水")
    
    Python

    3、作用之渲染模板(add.html)

    1 代码简单
    2 命名规范
    3 显示错误信息  # 方便显示,可以直接在模板中调用
    

    1、渲染方式一(常用)

    用for循环取出每一个字段,
    
    <h3>渲染方式3</h3>
    
    <form action="" method="post" novalidate>
        {% csrf_token %}
        {% for field in form %}  {# for循环取出每一个字段 #}
        <div>
            <label for="">{{ field.label }}</label>
            {{ field }} <span>{{ field.errors.0 }}</span>  {# 错误信息直接点出来 #}
        </div>
        {% endfor %}
    
         <input type="submit" value="submit">
    </form>
    
    HTML

    2、渲染方式二

    单独写每一个标签
    
    <h3>渲染方式2 </h3>
    
    <form action="" method="post" novalidate>
        {% csrf_token %}
        <div>
            <label for="">姓名</label>
            {{ form.name }} <span>{{ form.name.errors.0 }}</span>
        </div>
         <div>
            <label for="">年龄</label>
            {{ form.age }}<span>{{ form.age.errors.0 }}</span>
        </div>
         <div>
            <label for="">薪水</label>
            {{ form.salary }}<span>{{ form.salary.errors.0 }}</span>
        </div>
    
         <input type="submit" value="submit">
    </form>
    
    HTML

    3、渲染方式三

    自动生成,键名为类属性的名
    
    <h3>渲染方式1 </h3>
    <form action="" method="post">
        {% csrf_token %}
        {{ form.as_p }}
         <input type="submit" value="submit">
    </form>
    
    HTML

    4、显示错误与重置输入信息功能

    利用form表单刷新页面,显示用户输入的错误原因
    

    视图函数

    def addEmp(request):
    
        if request.method=="GET":
            form=EmpForm()  # 实例一个form组件对象
            return render(request,"add.html",locals())
    
        else:
            # print(request.POST)
            form=EmpForm(request.POST)
            if form.is_valid():  #  执行校验字段
                # print(form.cleaned_data)
                # print(form.errors)
                Emp.objects.create(**form.cleaned_data) # 所有的校验成功后,这里将数据添加进数据库,为该表格增加一条记录
                return HttpResponse("添加成功")
    
            else:
                # print(form.cleaned_data)
                # print(form.errors)    # 错误的存储方式为: {"name":["Ensure this value has at least 5 characters (it has 3).",]}
                return render(request, "add.html",{"form":form})
    
    Python

    模板

    <h3>渲染方式3</h3>
    
    <form action="" method="post" novalidate>
        {% csrf_token %}
        {% for field in form %}
        <div>
            <label for="">{{ field.label }}</label>
            {{ field }} <span>{{ field.errors.0 }}</span>
        </div>
        {% endfor %}
    
         <input type="submit" value="submit">
    </form>
    
    HTML

    5、钩子:灵活制定各种校验规则

    针对字段的,你写一个方法,检验一个字段,执行详细的检验规则,
    方法名要按规定写。def clear_类属性名():
    

    视图中的钩子

        #  钩子,灵活定制的校验规则
        def clean_name(self):  # 方法名固定写法,详细要求字段的规则
            val=self.cleaned_data.get("name")
            # 二次校验
            if val.isdigit(): # 校验是否是纯数字
                raise  ValidationError("姓名不能是纯数字!") # 根据校验规则,提示错误信息
            elif Emp.objects.filter(name=val):  # 检验是否在数据库已存在
                raise ValidationError("该员工已存在!")
            else:
                return val  # 必须把这个值返回
    
        def clean_age(self):
            val=self.cleaned_data.get("age")
            if int(val) > 100:
                raise ValidationError("年龄不能大于100!")
            else:
                return val
    
    Python

    6、基于ajax请求的信息校验(重点)

    视图

    from django.http import JsonResponse
    
    def addEmp(request):
        if request.is_ajax(): # 判断是否是ajax请求,判断是post请求也可以,只要不是GET请求,就执行验证逻辑
            form = EmpForm(request.POST)  # 实例化一个form对象,用于校验
            res={"state":True,"errors":None}
            if form.is_valid(): # 进行校验
                Emp.objects.create(**form.cleaned_data) # 全部成功添加进数据库
            else:
                res["state"]=False
                res["errors"]=form.errors  # 收集错误信息
            return JsonResponse(res)
        else:
            form = EmpForm()
            return render(request, "add.html", locals())
    
    Python

    模板中的HTML文件,ajax请求

    <h3>Ajax提交</h3>
    
    <form action="" method="post" novalidate>
        {% csrf_token %}
        {% for field in form %}
        <div>
            <label for="">{{ field.label }}</label>
            {{ field }} <span class="error"></span>
        </div>
        {% endfor %}
    
         <input type="button" class="ajax_btn" value="submit">
    </form>
    
    
    
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        (".ajax_btn").click(function () {           .ajax({
                url:"",    {# 不写就是默认当前地址重新发送 #}
                type:"post",
                data:{
                   "name":("#id_name").val(),                "age":("#id_age").val(),
                   "salary":("#id_salary").val(),                 csrfmiddlewaretoken:("[name='csrfmiddlewaretoken']").val()
                },
                success:function (res) {
                    console.log(res);
                    if (res.state){
                        console.log("添加成功!")
                    }else{
                        //  清空操作
                        ("span.error").html(""); {#  清空上一次的错误信息 #}                     //  循环显示错误信息                     .each(res.errors,function (key,value) {
                            console.log(key,value[0]);
    
                            $("#id_"+key).next().html(value[0])
                        })
    
                    }
                }
            })
    
        })
    </script>
    
    HTML

    二、用户认证组件

    Django自带的方便我们进行用户认证的组件,所有的request都会经过这个中间件
    
    大前提:
    这里使用的所有的API函数针对的是Django自带的auth_user表。
    

    1、auth模块

    auth模块提供功能:
    
    1 大前提:API函数针对的是django自带的auth_user----- 这个表是Django自带的,我们直接用,创建记录用命令创建
    
    2 为django下auth_user表创建用户:
            # 用命令创建,不要在表里直接输入
           python manage.py createsuperuser
    
    3  # user_obj=UserInfo.objects.filter(name=user,pwd=pwd).first()
        user_obj=auth.authenticate(username=user,password=pwd) # 查询有该对象,则返回对象(即校验用户名和密码),否则返回None
                                                                # authenticate
    
    4 auth.login(request,user_obj)
      # 1 注入session信息: # request.session["user_id"]=user_obj.pk
      # 下次用户再访问时就带着这个,经过中间件就会赋予代表其登录成功的状态,而不用再次登录
    
      # 2 request.user=user_obj
    
        # 补充
        request.user:
               (1) 之前函数执行login(),登录成功,request.user代表登录对象
               (2) AnonymousUser默认匿名用户对象,
                       request.user.id
                       request.user.username
    
    5 auth.logout(request)  # 注销当前用户的方法
    
    auth user对象的API:
         request.user.id
         request.user.is_authenticated()
    
    6 @login_required  # 用户认证组件自带的检验用户是否登录的装饰器
    
    
    7  创建用户
       auth_user表:from django.contrib.auth.models import User
       User.objects.create(username="alex",password="123")
       User.objects.create_user(username="alex",password="123")
       User.objects.create_superuser(username="alex",password="123")
    
    Python
    实例详解
    from django.contrib import auth # 引入自带的auth模块
    
    
    def login(request):
    
        if request.method=="GET": # get请求获取登录页面
            return render(request,"login.html")
        else:
            user = request.POST.get("user")
            pwd = request.POST.get("pwd")
            # user_obj=UserInfo.objects.filter(name=user,pwd=pwd).first()
            user_obj=auth.authenticate(username=user,password=pwd) # 查询有该对象,则返回对象,否则返回None
    
            if user_obj:
                # request.session["is_login"]=True
                # request.session["username"]=user # session方法的操作对比来看用户认证组件
                auth.login(request,user_obj) #  注入session信息: # request.session["user_id"]=user_obj.pk
                print(">>>>",request.user)
                print(request.path)
                print(request.get_full_path())
                print(request.GET.get("next")) # 拿到next的对应的路径,就是你在哪个页面点进来,登录成功后,返回那个页面
                path=request.GET.get("next") or "/index/"  # 通过简单的逻辑运算,如果是直接从登录页面进来的,就返回首页
                return redirect(path)
    
            return redirect("/login/")
    
    from django.contrib.auth.decorators import login_required
    
    @login_required  # 用户认证组件自带的检验用户是否登录的装饰器,功能跟注释的代码一样
    def index(request):
        # if not  request.user.id:
        #     return redirect("/login/")
        # print(request.user) # 当前登录用户
        return render(request,"index.html",locals())
    
    
    @login_required
    def order(request):  # 查看
        # if not  request.user.id:
        #     return redirect("/login/")
        # print(request.user) # 当前登录用户
        return render(request,"order.html")
    
    def logout(request):
        auth.logout(request) # 注销当前用户的方法
        return redirect("/login/")
    
    Python

    1、auth模块命令解析

    from django.contrib import auth
    django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:
    

    1、authenticate()

    提供了用户认证,即验证用户名以及密码是否正确,一般需要username  password两个关键字参数
    
    如果认证信息有效,会返回一个User 对象。
    authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,
    且该信息在后面的登录过程中是需要的。
    当我们试图登陆一个从数据库中直接取出来不经过authenticate()的User对象会报错的!!
    
    user = authenticate(username='someone',password='somepassword')
    

    2、login(HttpRequest, user)

    该函数接受一个HttpRequest对象,以及一个认证了的User对象
    
    此函数使用django的session框架给某个已认证的用户附加上session id等信息。
    
    from django.contrib.auth import authenticate, login
    
    def my_view(request):
      username = request.POST['username']
      password = request.POST['password']
      user = authenticate(username=username, password=password)
      if user is not None:
        login(request, user)  #  注入session信息: # request.session["user_id"]=user_obj.pk
        # Redirect to a success page.
        ...
      else:
        # Return an 'invalid login' error message.
        ...
    
    Python

    3、logout(request) 注销用户

    该函数接受一个HttpRequest对象,无返回值。
    当调用该函数时,当前请求的session信息会全部清除。
    
    该用户即使没有登录,使用该函数也不会报错。
    
    from django.contrib.auth import logout
    
    def logout_view(request):
      logout(request)
    
    Pyhton

    2、user对象的 is_authenticated()

    User 对象属性:username, password(必填项)password用哈希算法保存到数据库
    

    1、user对象的 is_authenticated()

    如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
    
    通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,
    这只是表明用户成功的通过了认证。
    
    这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,
    如果true则可以向前台展示request.user.name
    

    fe:要求

    要求:
    
    1  用户登陆后才能访问某些页面,
    
    2  如果用户没有登录就访问该页面的话直接跳到登录页面
    
    3  用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址
    
    方法1: 自己写逻辑
    def my_view(request):
      if not request.user.is_authenticated():
        return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
    
    方法2:
    django已经为我们设计好了一个用于此种情况的装饰器:login_requierd()
    
    
    from django.contrib.auth.decorators import login_required
    
    @login_required
    def my_view(request):
      ...
    
    若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' (
    这个值可以在settings文件中通过LOGIN_URL进行修改)。
    
    并传递  当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。
    
    Python

    2、创建用户

    使用 create_user 辅助函数创建用户:
    
    from django.contrib.auth.models import User
    user = User.objects.create_user(username='',password='',email='')
    

    3、check_password(passwd)

    用户需要修改密码的时候 首先要让他输入原来的密码 ,
    如果给定的字符串通过了密码检查,返回 True
    

    4、修改密码

    使用 set_password() 来修改密码
    
    user = User.objects.get(username='')
    user.set_password(password='')
    user.save 
    

    3、简单示例

    1、注册

    注册简单示例
    def sign_up(request):
    
        state = None
        if request.method == 'POST':
    
            password = request.POST.get('password', '')
            repeat_password = request.POST.get('repeat_password', '')
            email=request.POST.get('email', '')
            username = request.POST.get('username', '')
            if User.objects.filter(username=username):
                    state = 'user_exist'
            else:
                    new_user = User.objects.create_user(username=username, password=password,email=email)
                    new_user.save()
    
                    return redirect('/book/')
        content = {
            'state': state,
            'user': None,
        }
        return render(request, 'sign_up.html', content) 
    
    Python

    1、修改密码

    修改密码简单示例
    @login_required
    def set_password(request):
        user = request.user
        state = None
        if request.method == 'POST':
            old_password = request.POST.get('old_password', '')
            new_password = request.POST.get('new_password', '')
            repeat_password = request.POST.get('repeat_password', '')
            if user.check_password(old_password):
                if not new_password:
                    state = 'empty'
                elif new_password != repeat_password:
                    state = 'repeat_error'
                else:
                    user.set_password(new_password)
                    user.save()
                    return redirect("/log_in/")
            else:
                state = 'password_error'
        content = {
            'user': user,
            'state': state,
        }
        return render(request, 'set_password.html', content)
    
     
  • 相关阅读:
    安装pykeyboard模块
    Windows Defender Antivirus Service经常性出现占用CPU厉害
    Xpath 语法笔记
    通过docker部署rocketmq双主双从集群
    解决提取Mybatis多数据源公共组件“At least one base package must be specified”的问题
    设计模式-单例模式
    通过阳历生日计算星座,阴历生日,生辰八字,生肖五行
    设计模式-抽象工厂模式
    设计模式-工厂方法模式
    常用的MD5工具类
  • 原文地址:https://www.cnblogs.com/yipianshuying/p/10278454.html
Copyright © 2011-2022 走看看