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)
 
posted @ 2019-01-16 17:59  一片疏影  阅读(237)  评论(0编辑  收藏  举报