第六模块: WEB框架开发之Django框架开发学习笔记3

上接: 第六模块: WEB框架开发之Django框架开发学习笔记2

一百: forms组件的校验功能

参考:https://www.cnblogs.com/yuanchenqi/articles/9036474.html

100.1 校验就是检查用于输入的是否符合规范. 比如用户注册时,检查邮箱输入是否正确.

  Django中有专门用于校验的模块

100.2 实例: 用户注册页面,对用户输入进行校验

 

# views.py

from django.shortcuts import render, HttpResponse
from django import forms  # 引入表单验证的模块


class RegForm(forms.Form):
    """
    验证规则创建
    需要验证哪个表单项,就创建相应的方法
    """
    user = forms.CharField(min_length=2)  # 此处的user命名应当与html中表单的name值一致
    pwd = forms.CharField(min_length=4)  # 如果不加参数,则至少验证是否为空
    pwd2 = forms.CharField(min_length=4)
    email = forms.EmailField()
    tel = forms.IntegerField()


def reg(request):

    """
    # 验证的格式, 及验证详解
    ret = RegForm({'user': 'yuan', 'email': '123', "XXX": 'alex'})  # 对于class RegForm中没有定义的验证表单项,将不予理会"XXX": 'alex'
    print(ret.is_valid())  # 获取验证结果True/False, 只要有一条验证错误,就是False,当所有的验证通过,才显示True

    """

    if request.method == "POST":
        # 对用户输入内容进行验证
        ret = RegForm(request.POST)  # request.POST的返回值是一个字典{}, 和上面所讲的验证格式相符, 所以这里直接用.
        # print(ret)
        print(ret.is_valid())  # 获取验证结果True/False
        if ret.is_valid():
            print(ret.cleaned_data)  # 获取验证正确结果的详情{'user': 'alex', 'pwd': '1234', 'pwd2': '1234', 'email': '123@123.com', 'tel': 123}
        else:
            print(ret.cleaned_data)  # 获取所有正确的验证项目{'user': 'alex', 'tel': 123}
            print(ret.errors)  # 获取所有错误的验证项目,这里也是字典格式,比较特殊,下面是其返回值
            # <ul class="errorlist"><li>pwd<ul class="errorlist"><li>Ensure this value has at least 4 characters (it has 3).</li></ul></li><li>pwd2<ul class="errorlist"><li>Ensure this value has at least 4 characters (it has 3).</li></ul></li><li>email<ul class="errorlist"><li>Enter a valid email address.</li></ul></li></ul>
            print(type(ret.errors))  # <class 'django.forms.utils.ErrorDict'>  #
       print(ret.errors.get('email')[0]) # 通过get可取值.这里打印出 Enter a valid email address.
return render(request, 'reg.html')
# reg.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
</head>
<body>
    <form action="" method="post">
        {% csrf_token %}
        用户名<input type="text" name="user">
        密码<input type="text" name="pwd">
        确认密码<input type="text" name="pwd2">
        邮箱地址<input type="text" name="email">
        手机号码<input type="text" name="tel">
        <input type="submit">
    </form>

</body>
</html>

 

一百零一: forms组件的渲染标签功能1

参考:https://www.cnblogs.com/yuanchenqi/articles/9036474.html  标签渲染

101.1 html中的form表单中的标签可以通过Django的forms组件直接渲染而成.

101.2 这里还是是用户注册为例. 注意观察reg.html页面中的from表单中的标签,已经不是原来的<input>标签了.

最终效果:

查看上图渲染出的客户端浏览器代码:, 注意观察name值, id值

 

 

 源代码:

# views.py

from django.shortcuts import render, HttpResponse
from django import forms  # 引入forms模块

# Create your views here.


class RegForm(forms.Form):
    """
    验证规则创建,同时也将可以直接渲染至模板页面,成为html中form表单中的一个个标签.
    user将渲染成input标签的name属性值
    """
    user = forms.CharField(min_length=2, label='用户名')  # label='用户名' 将渲染至<label>标签中
    pwd = forms.CharField(min_length=4, label='密码')  # pwd将渲染成input标签的name属性值
    r_pwd = forms.CharField(min_length=4, label='确认密码')
    email = forms.EmailField(label='电子邮件')
    tel = forms.IntegerField(label='联系电话')


def reg(request):
    form = RegForm()  # 实例化forms对象, 这一步至关重要
    return render(request, 'reg.html', locals())  # locals()将form对象传递到html模板页面中去
# reg.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
</head>
<body>
    <h3>forms渲染标签功能1</h3>
    <form action="" method="post">  // <form>标签还是要的
        {% csrf_token %}
        <p>{{ form.user.label }}{{ form.user }}</p>  // 注意, 这里将要渲染出<labe>标签和<input>标签
        <p>{{ form.pwd.label }}{{ form.pwd }}</p>
        <p>{{ form.r_pwd.label }}{{ form.r_pwd }}</p>
        <p>{{ form.email.label }}{{ form.email }}</p>
        <p>{{ form.tel.label }}{{ form.tel }}</p>
        <input type="submit" value="提交" class="btn">  // 提交按钮的<input>标签不能丢
    </form>

</body>
</html>

 

一百零二: forms组件的渲染标签功能2

102.1 第二种渲染的方法将采用for循环取每一个渲染对象

102.2 接着第一种方法.第二中方法只修改html模板文件中的form表单内部就可以了,别的不用动.

最终效果和第一种方法是一样的:

源代码如下:

    <hr>
    <h3>forms渲染标签功能2</h3>
    <form action="" method="post">
        {% csrf_token %}
        {% for item in form %}  // for循环取值即可
            <p>{{ item.label }}{{ item }}</p>
        {% endfor %}
        <input type="submit" value="注册" class="btn">

    </form>

102.3 forms渲染标签的第三种方法,更加简单,但是不常用,一般只在测试代码时使用.关键代码{{ form.as_p }}

    <hr>
    <h3>forms渲染标签功能3</h3>
    <form action="" method="post">
        {% csrf_token %}
        {{ form.as_p }}  // as_p 表示按照<p>标签进行渲染.  还有.as_ul等属性表示按照<ul>标签进行渲染
        <input type="submit" value="注册" class="btn">
    </form>

第3中方法不常用的原因是: 格式固定,不太好根据需要修改页面.

 

一百零三: forms组件的渲染错误信息

103.1 比如当用户注册输错电子邮件格式时,能给予提示.

 

 html关键代码:

    <h3>forms组件的渲染错误信息</h3>
    <form action="" method="post">
        {% csrf_token %}
        <p>{{ form.user.label }}{{ form.user }}{{ form.user.errors.0 }}</p>
        <p>{{ form.pwd.label }}{{ form.pwd }}{{ form.pwd.errors.0 }}</p>
        <p>{{ form.r_pwd.label }}{{ form.r_pwd }}{{ form.r_pwd.errors.0 }}</p>
        <p>{{ form.email.label }}{{ form.email }}{{ form.email.errors.0 }}</p>
        <p>{{ form.tel.label }}{{ form.tel }}{{ form.tel.errors.0 }}</p>
        <input type="submit" value="提交" class="btn">
    </form>

views.py关键代码:

def reg(request):
    if request.method == 'POST':
        form = RegForm(request.POST)  # 对用户输入的表单内容进行验证
        if form.is_valid():  # 验证通过
            return HttpResponse('注册成功')
        else:  # 验证失败, 返回错误信息给客户端
            return render(request, 'reg.html', locals())

    form = RegForm()  # 实例化forms对象
    return render(request, 'reg.html', locals())  # locals()将form对象传递到html模板页面中去

103.2 forms表单渲染的完整代码:

from django.shortcuts import render, HttpResponse
from django import forms  # 引入forms模块

# Create your views here.


class RegForm(forms.Form):
    """
    验证规则创建,同时也将可以直接渲染至模板页面,成为html中form表单中的一个个标签.
    user将渲染成input标签的name属性值
    """
    user = forms.CharField(min_length=2, label='用户名')  # label='用户名' 将渲染至<label>标签中
    pwd = forms.CharField(min_length=4, label='密码')  # pwd将渲染成input标签的name属性值
    r_pwd = forms.CharField(min_length=4, label='确认密码')
    email = forms.EmailField(label='电子邮件')
    tel = forms.IntegerField(label='联系电话')


def reg(request):
    if request.method == 'POST':
        form = RegForm(request.POST)  # 对用户输入的表单内容进行验证
        if form.is_valid():  # 验证通过
            return HttpResponse('注册成功')
        else:  # 验证失败, 返回错误信息给客户端
            return render(request, 'reg.html', locals())

    form = RegForm()  # 实例化forms对象
    return render(request, 'reg.html', locals())  # locals()将form对象传递到html模板页面中去
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
</head>
<body>
    <h3>forms渲染标签功能1</h3>
    <form action="" method="post">
        {% csrf_token %}
        <p>{{ form.user.label }}{{ form.user }}</p>
        <p>{{ form.pwd.label }}{{ form.pwd }}</p>
        <p>{{ form.r_pwd.label }}{{ form.r_pwd }}</p>
        <p>{{ form.email.label }}{{ form.email }}</p>
        <p>{{ form.tel.label }}{{ form.tel }}</p>
        <input type="submit" value="提交" class="btn">
    </form>

    <hr>
    <h3>forms渲染标签功能2</h3>
    <form action="" method="post">
        {% csrf_token %}
        {% for item in form %}
            <p>{{ item.label }}{{ item }}</p>
        {% endfor %}
        <input type="submit" value="注册" class="btn">

    </form>

    <hr>
    <h3>forms渲染标签功能3</h3>
    <form action="" method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit" value="注册" class="btn">
    </form>

    <hr>
    <h3>forms组件的渲染错误信息</h3>
    <form action="" method="post">
        {% csrf_token %}
        <p>{{ form.user.label }}{{ form.user }}{{ form.user.errors.0 }}</p>
        <p>{{ form.pwd.label }}{{ form.pwd }}{{ form.pwd.errors.0 }}</p>
        <p>{{ form.r_pwd.label }}{{ form.r_pwd }}{{ form.r_pwd.errors.0 }}</p>
        <p>{{ form.email.label }}{{ form.email }}{{ form.email.errors.0 }}</p>
        <p>{{ form.tel.label }}{{ form.tel }}{{ form.tel.errors.0 }}</p>
        <input type="submit" value="提交" class="btn">
    </form>

</body>
</html>
View Code

104.3 需要说明的是新版的Django已经自动提供了错误渲染功能.所以就无需在在标签后面加上

{{ form.user.errors.0 }}了. views.py中的验证代码还是要加的.

 

一百零四: forms组件的参数配置

104.1 比如让input框变成密码框, 改变错误的提示内容等.增添修改标签的css样式等.

  引入参数配置功能模块 from django.forms import widgets

104.2 修改用户注册,实现效果如下:

 

 

 关键代码:注意这里借助了bootstrap.

class RegForm(forms.Form):
    """
    验证规则创建,同时也将可以直接渲染至模板页面,成为html中form表单中的一个个标签.
    user将渲染成input标签的name属性值
    """
    user = forms.CharField(min_length=2, label='用户名', error_messages={'required': '自定义错误提示:该字段不能为空'},
                           widget=widgets.TextInput(attrs={"class": "form-control"})  # 为该标签添加class属性,对css样式进行渲染
                           )
    pwd = forms.CharField(min_length=4, label='密码',
                          widget=widgets.PasswordInput(attrs={"class": "form-control"}),  # 将input输入框变成密码输入框
                          )
    r_pwd = forms.CharField(min_length=4, label='确认密码', widget=widgets.PasswordInput(attrs={"class": "form-control"}))
    email = forms.EmailField(label='电子邮件', error_messages={'invalid': '格式错误'}, widget=widgets.TextInput(attrs={"class": "form-control"}))
    tel = forms.IntegerField(label='联系电话', widget=widgets.TextInput(attrs={"class": "form-control"}))
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-lg-offset-3">
                    <h3>forms渲染标签功能1</h3>
                    <form action="" method="post">
                        {% csrf_token %}
                        <p>{{ form.user.label }}{{ form.user }}{{ form.user.errors.0 }}</p>
                        <p>{{ form.pwd.label }}{{ form.pwd }}{{ form.pwd.errors.0 }}</p>
                        <p>{{ form.r_pwd.label }}{{ form.r_pwd }}{{ form.r_pwd.errors.0 }}</p>
                        <p>{{ form.email.label }}{{ form.email }}{{ form.email.errors.0 }}</p>
                        <p>{{ form.tel.label }}{{ form.tel }}{{ form.tel.errors.0 }}</p>
                        <input type="submit" value="提交" class="btn">
                    </form>
            </div>
        </div>
    </div>

 

一百零五: forms组件校验的局部钩子

105.1 让校验条件更加灵活,比如判断用户名有么有注册过.比如校验手机号码是否是11位.

  需要引入一个模块from django.core.exceptions import ValidationError

105.2 实例:

 

 关键代码:

# views.py


class RegForm(forms.Form):
    """
    初步验证规则创建
    """
    name = forms.CharField(min_length=2, label='用户名', widget=widgets.TextInput(attrs={'class': "form-control"}))
    pwd = forms.CharField(min_length=4, label='密码', widget=widgets.PasswordInput(attrs={'class': "form-control"}))
    r_pwd = forms.CharField(min_length=4, label='确认密码', widget=widgets.PasswordInput(attrs={'class': "form-control"}))
    email = forms.EmailField(label='电子邮件', widget=widgets.TextInput(attrs={'class': "form-control"}))
    tel = forms.CharField(label='手机号码', widget=widgets.TextInput(attrs={'class': "form-control"}))

    """
    自定义验证规则(局部钩子)
    """
    def clean_name(self):  # 这里的函数名clean_name的格式是  clean_字段名
        # 定义验证用户名是否已经注册过
        val = self.cleaned_data.get('name')  # 从初步验证的结果中,再次取出数据
        ret = User.objects.filter(name=val)  # 从数据库中取数据
        if not ret:
            return val
        else:
            raise ValidationError("该用户已经注册过")

    def clean_tel(self):
        # 定义手机号码必须是11位数
        val = self.cleaned_data.get('tel')
        if len(val) == 11:
            return val
        else:
            raise ValidationError("手机号码必须是11位")

完整代码:

from django.shortcuts import render, HttpResponse
from django import forms  # 引入表单验证的模块
from django.forms import widgets  # 表单验证的附加功能,如添加css样式
from app01.models import User
from django.core.exceptions import ValidationError

# Create your views here.


class RegForm(forms.Form):
    """
    初步验证规则创建
    """
    name = forms.CharField(min_length=2, label='用户名', widget=widgets.TextInput(attrs={'class': "form-control"}))
    pwd = forms.CharField(min_length=4, label='密码', widget=widgets.PasswordInput(attrs={'class': "form-control"}))
    r_pwd = forms.CharField(min_length=4, label='确认密码', widget=widgets.PasswordInput(attrs={'class': "form-control"}))
    email = forms.EmailField(label='电子邮件', widget=widgets.TextInput(attrs={'class': "form-control"}))
    tel = forms.CharField(label='手机号码', widget=widgets.TextInput(attrs={'class': "form-control"}))

    """
    自定义验证规则(局部钩子)
    """
    def clean_name(self):  # 这里的函数名clean_name的格式是  clean_字段名
        # 定义验证用户名是否已经注册过
        val = self.cleaned_data.get('name')  # 从初步验证的结果中,再次取出数据
        ret = User.objects.filter(name=val)  # 从数据库中取数据
        if not ret:
            return val
        else:
            raise ValidationError("该用户已经注册过")

    def clean_tel(self):
        # 定义手机号码必须是11位数
        val = self.cleaned_data.get('tel')
        if len(val) == 11:
            return val
        else:
            raise ValidationError("手机号码必须是11位")


def reg(request):

    if request.method == "POST":
        # 对用户输入内容进行验证
        form = RegForm(request.POST)  # request.POST的返回值是一个字典{}, 和上面所讲的验证格式相符, 所以这里直接用.

        if form.is_valid():
            return HttpResponse("注册成功")
        else:
            return render(request, 'reg.html', locals())  # 返回验证错误的信息

    form = RegForm()
    return render(request, 'reg.html', locals())
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-lg-offset-3">
                <h3>forms组件校验的局部钩子</h3>
                <form action="" method="post">
                    {% csrf_token %}
                    {% for item in form %}
                        <p>{{ item.label }}{{ item }}<span>{{ item.errors.0 }}</span></p>
                    {% endfor %}
                    <input type="submit">
                </form>
            </div>
        </div>
    </div>
</body>
</html>
reg.html

 Django源代码中钩子的位置,正是使用了下面这个钩子,我们才可以进行自定义验证规则:

 

一百零六: forms组件之全局钩子

106.1 什么时候需要用全局钩子:

    比如校验两次输入的密码是否一致.

106.2 注意:forms的相关校验代码应当单独放到一个py文件中,尽量不要放在views.py视图文件中

106.3 实例, 全局钩子校验两次输入的密码是否一致:

 

 

 关键代码:

# app01下myforms.py(新建文件)

    """
    自定义验证规则(全局钩子)
    """
    def clean(self):
        # 定义两次输入的密码必须相同
        pwd = self.cleaned_data.get('pwd')
        r_pwd = self.cleaned_data.get('r_pwd')
        if pwd == r_pwd:
            return self.cleaned_data  # 如果没有错误,则原封不动返回
        else:
            raise ValidationError("两次输入密码不一致")
# views.py中获取全局钩子错误

def reg(request):

    if request.method == "POST":
        # 对用户输入内容进行验证
        form = RegForm(request.POST)  # request.POST的返回值是一个字典{}, 和上面所讲的验证格式相符, 所以这里直接用.

        if form.is_valid():
            return HttpResponse("注册成功")
        else:
            # 全局钩子错误
            # print(form.errors.get("__all__")[0])
            error_all = form.errors.get("__all__")  # 获取全局错误

            return render(request, 'reg.html', locals())  # 返回验证错误的信息

    form = RegForm()
    return render(request, 'reg.html', locals())
# 在reg.html中的确认密码处显示全局钩子错误 error_all.0

                    <p>{{ form.r_pwd.label }}{{ form.r_pwd }}
                        <span class="pull-right error">{{ form.r_pwd.errors.0 }}</span>
                        <span class="pull-right error">{{ error_all.0 }}</span>
                    </p>

完整代码:

from django.shortcuts import render, HttpResponse

from app01.myforms import RegForm  # 引入自定义的forms组件校验模块


def reg(request):

    if request.method == "POST":
        # 对用户输入内容进行验证
        form = RegForm(request.POST)  # request.POST的返回值是一个字典{}, 和上面所讲的验证格式相符, 所以这里直接用.

        if form.is_valid():
            return HttpResponse("注册成功")
        else:
            # 全局钩子错误
            # print(form.errors.get("__all__")[0])
            error_all = form.errors.get("__all__")  # 获取全局错误

            return render(request, 'reg.html', locals())  # 返回验证错误的信息

    form = RegForm()
    return render(request, 'reg.html', locals())
views.py
# -*- coding: utf-8 -*-
# programming environment:windows7_64 + python3.8.3_64

from django import forms  # 引入表单验证的模块
from django.forms import widgets  # 表单验证的附加功能,如添加css样式
from app01.models import User
from django.core.exceptions import ValidationError


class RegForm(forms.Form):
    """
    初步验证规则创建
    """
    name = forms.CharField(min_length=2, label='用户名', widget=widgets.TextInput(attrs={'class': "form-control"}))
    pwd = forms.CharField(min_length=4, label='密码', widget=widgets.PasswordInput(attrs={'class': "form-control"}))
    r_pwd = forms.CharField(min_length=4, label='确认密码', widget=widgets.PasswordInput(attrs={'class': "form-control"}))
    email = forms.EmailField(label='电子邮件', widget=widgets.TextInput(attrs={'class': "form-control"}))
    tel = forms.CharField(label='手机号码', widget=widgets.TextInput(attrs={'class': "form-control"}))

    """
    自定义验证规则(局部钩子)
    """
    def clean_name(self):  # 这里的函数名clean_name的格式是  clean_字段名
        # 定义验证用户名是否已经注册过
        val = self.cleaned_data.get('name')  # 从初步验证的结果中,再次取出数据
        ret = User.objects.filter(name=val)  # 从数据库中取数据
        if not ret:
            return val
        else:
            raise ValidationError("该用户已经注册过")

    def clean_tel(self):
        # 定义手机号码必须是11位数
        val = self.cleaned_data.get('tel')
        if len(val) == 11:
            return val
        else:
            raise ValidationError("手机号码必须是11位")

    """
    自定义验证规则(全局钩子)
    """
    def clean(self):
        # 定义两次输入的密码必须相同
        pwd = self.cleaned_data.get('pwd')
        r_pwd = self.cleaned_data.get('r_pwd')
        if pwd == r_pwd:
            return self.cleaned_data  # 如果没有错误,则原封不动返回
        else:
            raise ValidationError("两次输入密码不一致")
myforms.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-lg-offset-3">
                <h3>forms组件之全局钩子</h3>
                <form action="" method="post">
                    {% csrf_token %}
                    <p>{{ form.name.label }}{{ form.name }}<span class="pull-right error">{{ form.name.errors.0 }}</span></p>
                    <p>{{ form.pwd.label }}{{ form.pwd }}<span class="pull-right error">{{ form.pwd.errors.0 }}</span></p>
                    <p>{{ form.r_pwd.label }}{{ form.r_pwd }}
                        <span class="pull-right error">{{ form.r_pwd.errors.0 }}</span>
                        <span class="pull-right error">{{ error_all.0 }}</span>
                    </p>
                    <p>{{ form.email.label }}{{ form.email }}<span class="pull-right error">{{ form.email.errors.0 }}</span></p>
                    <p>{{ form.tel.label }}{{ form.tel }}<span class="pull-right error">{{ form.tel.errors.0 }}</span></p>
                    <input type="submit">
                </form>
            </div>
        </div>
    </div>
</body>
</html>
reg.html
from django.db import models

# Create your models here.
class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    email = models.EmailField()
    tel = models.IntegerField(max_length=11)
models.py

 

一百零七: HTTP协议的无状态保存

服务器对于客户的每一次访问,它都认为是全新的.然而我们经常需要知道用户是否已经访问过,然后针对访问过的用户展示不同的内容.

这就需要用到cookie和session

一百零八: cookie简介

参考:https://www.cnblogs.com/yuanchenqi/articles/9036467.html

cookie: 具体一个浏览器针对一个服务器存储key-value({})

cookie的数据是存储在浏览器本地的.浏览器第一次访问某个网站时会携带空字典的cookie,如果服务器端有相关的cookie处理视图则会返回到客户端的cookie中,当下次再访问该网站时就会携带该有数据的cookie访问网站.常用于用户登录.

 

 

 

 

 

 

一百零九: cookie的设置与读取

109.1 关键代码:设置cookie

def login(request):
    if request.method == "POST":
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')

        ret = UserInfo.objects.filter(name=name, pwd=pwd).first()
        if ret:
            """
            响应体
            return HttpResponse()
            return render()
            return redirect()
            """
            response = HttpResponse('登录成功')
            response.set_cookie('is_login', True)  # 设置cookies
            response.set_cookie('name', ret.name)  # 设置cookies

            return response
  return render(request, 'login.html')

  关键代码 读取cookie

def index(request):
    is_login = request.COOKIES.get('is_login')  # 获取cookies
    if is_login:
        name = request.COOKIES.get('name')  # 获取cookies
        return render(request, 'index.html', {'name': name})
    return redirect('/login/')

  登录成功后index的显示效果:

 

 

  检查网页客户端,发现的cookie信息如下:和设置的cookies一致 

 

 

 

109.2 实例,验证用户是否登录过本网站,如果没有登录,则返回登录页面.

from django.db import models

# Create your models here.


class UserInfo(models.Model):

    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
models.py
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('add/', views.add),
    path('login/', views.login),
    path('index/', views.index),
]
urls.py
from django.shortcuts import render, redirect, HttpResponse
from app01.models import UserInfo

# Create your views here.


def add(request):
    UserInfo.objects.create(name='alex', pwd='123')
    UserInfo.objects.create(name='papa', pwd='456')

    return HttpResponse('新建数据完成!')


def login(request):
    if request.method == "POST":
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')

        ret = UserInfo.objects.filter(name=name, pwd=pwd).first()
        if ret:
            """
            响应体
            return HttpResponse()
            return render()
            return redirect()
            """
            response = HttpResponse('登录成功')
            response.set_cookie('is_login', True)  # 设置cookies
            response.set_cookie('name', ret.name)  # 设置cookies

            return response

    return render(request, 'login.html')


def index(request):
    print(request.COOKIES)
    is_login = request.COOKIES.get('is_login')  # 获取cookies
    if is_login:
        name = request.COOKIES.get('name')  # 获取cookies
        return render(request, 'index.html', {'name': name})
    return redirect('/login/')
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>用户登录</h3>
    <form action="" method="post">
        {% csrf_token %}
        用户名<input type="text" name="name">
        密码<input type="text" name="pwd">
        <input type="submit">
    </form>

</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>你好, {{ name }}!</h3>

</body>
</html>
index.html

 

一百一十: 设置cookie的超时参数

参考:https://www.cnblogs.com/yuanchenqi/articles/9036467.html

超过设置的时间后,浏览器中携带的cookie将失效.

110.1 设置cookie的有效时间,超过这个时间则已经获取的cookie失效, 参数max_age默认为None, 即浏览器关闭后失效.

response.set_cookie('is_login', True, max_age=10)  # 设置cookie, 10秒后is_login==False

110.2 设置cookie失效的指定日期时间点,参数expires默认值是None

import datetime
date = datetime.datetime(year=2021, month=2, day=21, hour=2, minute=38, second=0)  # 指定过期日期, 因为我们是东八区,所有hour要减去8
response.set_cookie('name', ret.name, expires=date)  # 设置cookies

 

一百一十一: 设置cookie的有效路径

参数path默认是所有路径都有效.

response.set_cookie('name', ret.name, path='/index/')  # 设置有效路径, index这个路径才有包含name的cookie

一百一十二: cookie应用之保存上次访问时间

112.1 删除cookie

response.delete_cookie("cookie_key", path='/', domain=name)  # 删除cookies的操作

  还可以直接在浏览器中清空cookie

 112.2 客户端显示上次登录时间

 

 

 

 关键代码:

def index(request):
    print(request.COOKIES)
    is_login = request.COOKIES.get('is_login')  # 获取cookies
    if is_login:
        name = request.COOKIES.get('name')  # 获取cookies
        import datetime
        now_time = datetime.datetime.now().strftime("%Y-%m-%d %X")  # 设置当前时间
        last_time = request.COOKIES.get('last_time', '')  # 获取cookie中的上次登录时间, 取不到时间则默认为空
        response = render(request, 'index.html', {'name': name, 'now_time': now_time, 'last_time': last_time})
        response.set_cookie('last_time', now_time)  # 把本次登录时间设置到cookie中
        return response
    return redirect('/login/')

 

一百一十三: session的流程简介

参考:https://www.cnblogs.com/yuanchenqi/articles/9036467.html     session

也是一个会话跟踪技术

113.1 session是服务端技术,是基于cookie开发的.主要是基于安全考虑.

cookies将数据存到客户端, session将数据存储到服务端.

session相当于你去澡堂洗澡,你的衣服放在澡堂的柜子里面,session就是柜子号牌钥匙.你通过柜子号牌钥匙就可以取到衣服.

 113.2 数据库中自动创建的django_session表

 

 

 

 

一一四: session之保存登录状态信息

 114.1 设置session的值,request.session['is_login']=True,注意每设置一次session值,django做了三件事

def login_session(request):

    if request.method == "POST":
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')

        ret = UserInfo.objects.filter(name=name, pwd=pwd).first()
        if ret:
            request.session['is_login'] = True  # 设置session值
            """
            # 每设置一次session值,django做了三件事
            1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c
            2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c')
            3. 在django-session表中创建一条记录:
                    session-key                                 session-data
                59b3k5f9fxpg17t2ikdoh7x787axaz8c        {'is_login': True}  # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs
            """
            request.session['name'] = ret.name  # 设置session值

            return HttpResponse('登录成功')

    return render(request, "login.html")

114.2 读取session的值, request.session.get('is_login'),注意每读取一次session值,django也做了三件事

def index_session(request):

    is_login = request.session.get('is_login')  # 读取session值
    """
    # 每读取一次session值,django也做了三件事
    1. request.COOKIE.get("is_login")  59b3k5f9fxpg17t2ikdoh7x787axaz8c
    2. django-session表中过滤记录
        django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c')
    3. 取出'is_login'值
        obj.session-data.get('is_login')
    """
    if is_login:
        name = request.session.get('name')  # 读取session值
        return render(request, 'index.html', {'name': name})

    return redirect('/login_session/')

114.3 完整代码:

from django.shortcuts import render, redirect, HttpResponse
from app01.models import UserInfo

# Create your views here.


def add(request):
    UserInfo.objects.create(name='alex', pwd='123')
    UserInfo.objects.create(name='papa', pwd='456')

    return HttpResponse('新建数据完成!')


def login(request):
    if request.method == "POST":
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')

        ret = UserInfo.objects.filter(name=name, pwd=pwd).first()
        if ret:
            """
            响应体
            return HttpResponse()
            return render()
            return redirect()
            """
            response = HttpResponse('登录成功')
            response.set_cookie('is_login', True, max_age=None)  # 设置cookies

            import datetime
            # date = datetime.datetime(year=2021, month=2, day=21, hour=2, minute=38, second=0)  # 指定过期日期, 因为我们是东八区,所有hour要减去8
            # response.set_cookie('name', ret.name, expires=date)  # 设置cookies
            response.set_cookie('name', ret.name, path='/index/')  # 设置有效路径, index这个路径才有包含name的cookie

            return response

    return render(request, 'login.html')


def index(request):
    print(request.COOKIES)
    is_login = request.COOKIES.get('is_login')  # 获取cookies
    if is_login:
        name = request.COOKIES.get('name')  # 获取cookies
        import datetime
        now_time = datetime.datetime.now().strftime("%Y-%m-%d %X")  # 设置当前时间
        last_time = request.COOKIES.get('last_time', '')  # 获取cookie中的上次登录时间, 取不到时间则默认为空
        response = render(request, 'index.html', {'name': name, 'now_time': now_time, 'last_time': last_time})
        response.set_cookie('last_time', now_time)  # 把本次登录时间设置到cookie中
        return response
    return redirect('/login/')


def login_session(request):

    if request.method == "POST":
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')

        ret = UserInfo.objects.filter(name=name, pwd=pwd).first()
        if ret:
            request.session['is_login'] = True  # 设置session值
            """
            # 每设置一次session值,django做了三件事
            1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c
            2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c')
            3. 在django-session表中创建一条记录:
                    session-key                                 session-data
                59b3k5f9fxpg17t2ikdoh7x787axaz8c        {'is_login': True}  # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs
            """
            request.session['name'] = ret.name  # 设置session值

            return HttpResponse('登录成功')

    return render(request, "login.html")


def index_session(request):

    is_login = request.session.get('is_login')  # 读取session值
    """
    # 每读取一次session值,django也做了三件事
    1. request.COOKIE.get("is_login")  59b3k5f9fxpg17t2ikdoh7x787axaz8c
    2. django-session表中过滤记录
        django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c')
    3. 取出'is_login'值
        obj.session-data.get('is_login')
    """
    if is_login:
        name = request.session.get('name')  # 读取session值
        return render(request, 'index.html', {'name': name})

    return redirect('/login_session/')
views.py
"""cookieSession URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('add/', views.add),
    path('login/', views.login),
    path('index/', views.index),

    path('login_session/', views.login_session),
    path('index_session/', views.index_session),
]
urls.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>你好, {{ name }}!</h3>
    <h4>上次登录时间{{ last_time }}</h4>
    <h4>本次登录时间{{ now_time }}</h4>

</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>用户登录</h3>
    <form action="" method="post">
        {% csrf_token %}
        用户名<input type="text" name="name">
        密码<input type="text" name="pwd">
        <input type="submit">
    </form>

</body>
</html>
login.html

114.4 效果:

  django_session表中生成的记录

 

   浏览器客户端cookies中存储的值

 

一一五: session应用之保存上次登录时间

115.1 先看效果

 

 115.2 设置session的值, 记录登录时间.

def login_session(request):

    if request.method == "POST":
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')

        ret = UserInfo.objects.filter(name=name, pwd=pwd).first()
        if ret:
            request.session['is_login'] = True  # 设置session值
            """
            # 每设置一次session值,django做了三件事
            1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c
            2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c')
            3. 在django-session表中创建一条记录:
                    session-key                                 session-data
                59b3k5f9fxpg17t2ikdoh7x787axaz8c        {'is_login': True}  # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs
            """
            request.session['name'] = ret.name  # 设置session值

            import datetime
            now_time = datetime.datetime.now().strftime('%Y-%m-%d %X')
            request.session['last_time'] = now_time  # 设置session值, 记录用户登录时间


            return HttpResponse('登录成功')

    return render(request, "login.html")

115.3 读取session中登录的时间

def index_session(request):

    is_login = request.session.get('is_login')  # 读取session值
    """
    # 每读取一次session值,django也做了三件事
    1. request.COOKIE.get("is_login")  59b3k5f9fxpg17t2ikdoh7x787axaz8c
    2. django-session表中过滤记录
        django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c')
    3. 取出'is_login'值
        obj.session-data.get('is_login')
    """
    if is_login:
        name = request.session.get('name')  # 读取session值

        last_time = request.session.get('last_time')  # 读取session值, 上次用户登录时间

        return render(request, 'index.html', {'name': name, 'last_time': last_time})

    return redirect('/login_session/')

 

一一六: session的更新操作

没有单独的更新操作的方法,更新操作就用上面的设置session方法.

接上节课,当对session执行设置操作时,如果该客户端的该浏览器已经设置过session,则有新数据时,就只更新session中的相应记录,而不会新增记录, session-key不会变,session-data数据更新.

比如:A电脑的谷歌浏览器上午用alex用户登录过该网页,下午还是用A电脑的谷歌浏览器,但用户变成了papa登录,这时django不会新增sessionid,还用上午的那个sessionid,然后修改表中对应的session-data数据.原有的alex登录数据就被覆盖了.

 

一一七: 基于session的注销功能与session的配置参数

参考:https://www.cnblogs.com/yuanchenqi/articles/9036467.html 

117.1 注销功能, 使用flush()方法

def logout(request):

    # del request.session['is_login']  # 删除session中某个键值, 一般不用这个

    request.session.flush()  # 删除表中当前session一整条记录, 还会删除客户端浏览器的cookie相应的记录
    """
    # flush()操作也做了三件事
    1. randon_str = request.COOKIE.get('sessionid')  获取cookie中的sessionid
    2. django-session.objects.filter(session-key=randon_str).delete()  从表中过滤出该条记录,并删除掉
    3. response.delete_cookie('sessionid', randon_str)  删除客户端浏览器的cookie记录
    """

    return redirect('/login_session/')

 

 完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>你好, {{ name }}!</h3>
    <h4>上次登录时间{{ last_time }}</h4>
    <h4>本次登录时间{{ now_time }}</h4>
    <a href="/logout">注销</a>

</body>
</html>
View Code
"""cookieSession URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('add/', views.add),
    path('login/', views.login),
    path('index/', views.index),

    path('login_session/', views.login_session),
    path('index_session/', views.index_session),

    path('logout/', views.logout),

]
urls.py
from django.shortcuts import render, redirect, HttpResponse
from app01.models import UserInfo

# Create your views here.


def add(request):
    UserInfo.objects.create(name='alex', pwd='123')
    UserInfo.objects.create(name='papa', pwd='456')

    return HttpResponse('新建数据完成!')


def login(request):
    if request.method == "POST":
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')

        ret = UserInfo.objects.filter(name=name, pwd=pwd).first()
        if ret:
            """
            响应体
            return HttpResponse()
            return render()
            return redirect()
            """
            response = HttpResponse('登录成功')
            response.set_cookie('is_login', True, max_age=None)  # 设置cookies

            import datetime
            # date = datetime.datetime(year=2021, month=2, day=21, hour=2, minute=38, second=0)  # 指定过期日期, 因为我们是东八区,所有hour要减去8
            # response.set_cookie('name', ret.name, expires=date)  # 设置cookies
            response.set_cookie('name', ret.name, path='/index/')  # 设置有效路径, index这个路径才有包含name的cookie

            return response

    return render(request, 'login.html')


def index(request):
    print(request.COOKIES)
    is_login = request.COOKIES.get('is_login')  # 获取cookies
    if is_login:
        name = request.COOKIES.get('name')  # 获取cookies
        import datetime
        now_time = datetime.datetime.now().strftime("%Y-%m-%d %X")  # 设置当前时间
        last_time = request.COOKIES.get('last_time', '')  # 获取cookie中的上次登录时间, 取不到时间则默认为空
        response = render(request, 'index.html', {'name': name, 'now_time': now_time, 'last_time': last_time})
        response.set_cookie('last_time', now_time)  # 把本次登录时间设置到cookie中
        return response
    return redirect('/login/')


def login_session(request):

    if request.method == "POST":
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')

        ret = UserInfo.objects.filter(name=name, pwd=pwd).first()
        if ret:
            request.session['is_login'] = True  # 设置session值
            """
            # 每设置一次session值,django做了三件事
            1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c
            2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c')
            3. 在django-session表中创建一条记录:
                    session-key                                 session-data
                59b3k5f9fxpg17t2ikdoh7x787axaz8c        {'is_login': True}  # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs
            """
            request.session['name'] = ret.name  # 设置session值

            import datetime
            now_time = datetime.datetime.now().strftime('%Y-%m-%d %X')
            request.session['last_time'] = now_time  # 设置session值, 记录用户登录时间


            return HttpResponse('登录成功')

    return render(request, "login.html")


def index_session(request):

    is_login = request.session.get('is_login')  # 读取session值
    """
    # 每读取一次session值,django也做了三件事
    1. request.COOKIE.get("is_login")  59b3k5f9fxpg17t2ikdoh7x787axaz8c
    2. django-session表中过滤记录
        django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c')
    3. 取出'is_login'值
        obj.session-data.get('is_login')
    """
    if is_login:
        name = request.session.get('name')  # 读取session值

        last_time = request.session.get('last_time')  # 读取session值, 上次用户登录时间

        return render(request, 'index.html', {'name': name, 'last_time': last_time})

    return redirect('/login_session/')

def logout(request):

    # del request.session['is_login']  # 删除session中某个键值, 一般不用这个

    request.session.flush()  # 删除表中当前session一整条记录, 还会删除客户端浏览器的cookie相应的记录
    """
    # flush()操作也做了三件事
    1. randon_str = request.COOKIE.get('sessionid')  获取cookie中的sessionid
    2. django-session.objects.filter(session-key=randon_str).delete()  从表中过滤出该条记录,并删除掉
    3. response.delete_cookie('sessionid', randon_str)  删除客户端浏览器的cookie记录
    """

    return redirect('/login_session/')
views.py

117.2 session的配置参数

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
   
a. 配置 settings.py, 在settings.py中新增以下需要的项目.
   
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
       
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
settings.py

一一八: session总结

需要掌握的的内容:

1. 写cookie操作    response.set_cookie(key, value)

2. 读cookie操作    request.COOKIE.get(key)

3. 写(设置)session操作  request.session[key] = value
    """
    # 每设置一次session值,django做了三件事
    1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c
    2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c')
    3. 在django-session表中创建一条记录:
            session-key                                 session-data
        59b3k5f9fxpg17t2ikdoh7x787axaz8c        {'is_login': True}  # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs
    """

4. 读取session操作  request.session.get[key]
    """
    # 每读取一次session值,django也做了三件事
    1. request.COOKIE.get("is_login")  59b3k5f9fxpg17t2ikdoh7x787axaz8c
    2. django-session表中过滤记录
        django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c')
    3. 取出'is_login'值
        obj.session-data.get('is_login')
    """
    
5. 删除session操作  request.session.flush()
    """
    # flush()操作也做了三件事
    1. randon_str = request.COOKIE.get('sessionid')  获取cookie中的sessionid
    2. django-session.objects.filter(session-key=randon_str).delete()  从表中过滤出该条记录,并删除掉
    3. response.delete_cookie('sessionid', randon_str)  删除客户端浏览器的cookie记录
    """

 

一一九: 用户认证组件简介

参考:https://www.cnblogs.com/yuanchenqi/articles/9064397.html  

119.1 使用cookie,session会出现一些问题,多用户使用时会数据会混淆

119.2 使用用户认证组件会使程序更完善,更严谨,可以避免出现数据混淆等错误.推荐使用该组件.

  auth模块  from django.contrib import auth

119.2 用户认证组件说明:

  功能: 用session记录登录验证状态

  前提: 用户表: Django自带auth_user表   (该表字段比较多,可能不符合自己的需求,怎么办?可以根据自己需要新建新表,然后关联到auth_user表,或者继承该表.)

    先进行迁移生成数据库,表.

    然后,创建超级用户: 命令:python manage.py createsuperuser

  

 

一二0: 基于用户认证组件的登录验证信息存储

120.1 用户登录验证, 并存储信息.

from django.shortcuts import render, redirect, HttpResponse
from django.contrib import auth  # 导入用户认证组件

def login(request):

    if request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')

        # if 验证成功返回user对象,否则返回None. 注意这里的表里的password是加密文,所以有别与以前的表查询fillter筛选
        user = auth.authenticate(username=user, password=pwd)  # 与表中记录进行验证(相当于fillter筛选)
        if user:

            # request.user=user就是当前登录对象,它是全局变量,可以在任意地方直接使用, 这里非常重要,将自动向session表添加记录.
            auth.login(request, user)
            # 如果没有登录,则是匿名对象.
            return redirect('/index/')

    return render(request, 'login.html')

120.2 读取登录用户的信息,并在模板显示

from django.shortcuts import render, redirect, HttpResponse
from django.contrib import auth  # 导入用户认证

def index(request):
    print(request.user)  # 打印当前用户对象, request.user是全局变量.
    print(request.user.username)  # 打印当前用户
    print(request.user.id)  # 用户id,匿名用户是None
    print(request.user.is_anonymous)  # 是否是匿名用户

    if request.user.is_anonymous:  # 如果是匿名用户(就是没有登录),则跳转到登录页面.
        return redirect('/login/')

    # username = request.user.username  # 这一步可以省略了.

    return render(request, 'index.html')  # 这里省略了向模板传递参数.因为request.user是全局变量,甚至可以直接用在模板中.
    # 如果没有登录,那么request.user显示匿名用户AnonymousUser

120.3 使用request.user.username全局变量,在模板中显示用户登录信息.

<h3>你好, {{ request.user.username }}</h3>

120.4 完整代码

"""authDemo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
]
urls.py
from django.shortcuts import render, redirect, HttpResponse
from django.contrib import auth  # 导入用户认证组件

def login(request):

    if request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')

        # if 验证成功返回user对象,否则返回None. 注意这里的表里的password是加密文,所以有别与以前的表查询fillter筛选
        user = auth.authenticate(username=user, password=pwd)  # 与表中记录进行验证(相当于fillter筛选)
        if user:

            # request.user=user就是当前登录对象,它是全局变量,可以在任意地方直接使用, 这里非常重要,将自动向session表添加记录.
            auth.login(request, user)
            # 如果没有登录,则是匿名对象.
            return redirect('/index/')

    return render(request, 'login.html')


def index(request):
    print(request.user)  # 打印当前用户对象, request.user是全局变量.
    print(request.user.username)  # 打印当前用户
    print(request.user.id)  # 用户id,匿名用户是None
    print(request.user.is_anonymous)  # 是否是匿名用户

    if request.user.is_anonymous:  # 如果是匿名用户(就是没有登录),则跳转到登录页面.
        return redirect('/login/')

    # username = request.user.username  # 这一步可以省略了.

    return render(request, 'index.html')  # 这里省略了向模板传递参数.因为request.user是全局变量,甚至可以直接用在模板中.
    # 如果没有登录,那么request.user显示匿名用户AnonymousUser
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>用户登录</h3>
    <form action="" method="post">
        {% csrf_token %}
        用户名<input type="text" name="user">
        密码<input type="text" name="pwd">
        <input type="submit">
    </form>


</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
        <h3>你好, {{ request.user.username }}</h3>
</body>
</html>
index.html

 

一二一: 基于用户认证组件的注销功能

def logout(request):

    auth.logout(request)  # 注销会删除session表中的记录

    return redirect('/login/')

 

一二二: 基于用户认证组件的注册用户功能

 122.1 关键代码

from django.shortcuts import render, redirect, HttpResponse
from django.contrib import auth
from django.contrib.auth.models import User  # 导入用户表模块,对应数据库中的auth_user表

def reg(request):
    if request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')

        # create_user创建普通用户
        # User.objects.create(username=user, password=pwd) 不能用create因为password是需要加密的
        User.objects.create_user(username=user, password=pwd)  # 写入用户信息到auth_user表中
        return redirect('/login/')  # 注册成功则跳转到登录页面

    return render(request, 'reg.html')

122.2 项目完整代码

from django.shortcuts import render, redirect, HttpResponse
from django.contrib import auth
from django.contrib.auth.models import User  # 导入用户表模块,对应数据库中的auth_user表

def login(request):

    if request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')

        # if 验证成功返回user对象,否则返回None. 注意这里的表里的password是加密文,所以有别与以前的表查询fillter筛选
        user = auth.authenticate(username=user, password=pwd)  # 与表中记录进行验证(相当于fillter筛选)
        if user:

            # request.user=user就是当前登录对象,它是全局变量,可以在任意地方直接使用, 这里非常重要,将自动向session表添加记录.
            auth.login(request, user)
            # 如果没有登录,则是匿名对象.
            return redirect('/index/')

    return render(request, 'login.html')


def index(request):
    print(request.user)  # 打印当前用户对象, request.user是全局变量.
    print(request.user.username)  # 打印当前用户
    print(request.user.id)  # 用户id,匿名用户是None
    print(request.user.is_anonymous)  # 是否是匿名用户

    # if not request.user.is_authenticated:  # 判断该用户是否登录过, 和下面的一行,效果一样.
    if request.user.is_anonymous:  # 如果是匿名用户(就是没有登录),则跳转到登录页面.

        return redirect('/login/')

    # username = request.user.username  # 这一步可以省略了.

    return render(request, 'index.html')  # 这里省略了向模板传递参数.因为request.user是全局变量,甚至可以直接用在模板中.
    # 如果没有登录,那么request.user显示匿名用户AnonymousUser


def logout(request):

    auth.logout(request)  # 注销会删除session表中的记录

    return redirect('/login/')


def reg(request):
    if request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')

        # create_user创建普通用户
        # User.objects.create(username=user, password=pwd) 不能用create因为password是需要加密的
        User.objects.create_user(username=user, password=pwd)  # 写入用户信息到auth_user表中
        return redirect('/login/')  # 注册成功则跳转到登录页面

    return render(request, 'reg.html')
views.py
"""authDemo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    path('reg/', views.reg),
]
urls.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>注册</h3>
    <form action="" method="post">
        {% csrf_token %}
        用户名<input type="text" name="user">
        密码<input type="text" name="pwd">
        <input type="submit">
    </form>


</body>
</html>
reg.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>用户登录</h3>
    <form action="" method="post">
        {% csrf_token %}
        用户名<input type="text" name="user">
        密码<input type="text" name="pwd">
        <input type="submit">
    </form>


</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>你好, {{ request.user.username }}</h3>
    <a href="/logout/">注销</a>
</body>
</html>
index.html

 112.3 修改密码

 

 112.4 用户认证组件总结

用户认证组件最重要的API:

    from django.contrib import auth
        1. # if 验证成功返回user对象,否则返回None. 注意这里的表里的password是加密文,所以有别与以前的表查询fillter筛选
            user = auth.authenticate(username=user, password=pwd)

        2. auth.login(request, user)  # request.user:当前登录对象

        3. auth.logout(request)  # 注销会删除session表中的记录

    from django.contrib.auth.models import User # User==auth_user

        4. request.user.is_authenticated:  # 判断该用户是否登录过

        5. User.objects.create_user(username=user, password=pwd)  # 写入用户信息到auth_user表中

    补充:

        匿名用户对象:  参考:https://www.cnblogs.com/yuanchenqi/articles/8876856.htmlni匿名用户
            匿名用户
            class models.AnonymousUser
        
            django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
        
            id 永远为None。
            username 永远为空字符串。
            get_username() 永远返回空字符串。
            is_staff 和 is_superuser 永远为False。
            is_active 永远为 False。
            groups 和 user_permissions 永远为空。
            is_anonymous() 返回True 而不是False。
            is_authenticated() 返回False 而不是True。
            set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
            New in Django 1.8:
            新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。

    总结:

        if not: auth.login(request, user)  request.user == AnonymousUser()

        else:request.user==登录对象

        request.user是一个全局变量,在任何视图和模板中直接使用

 

一二三: 基于用户认证组件的认证装饰器

123.1 关键代码

# settings.py中添加下面的常量
LOGIN_URL = '/login/'  # 设置跳转的路径(设置认证装饰器时使用)

 

from django.contrib.auth.decorators import login_required  # 认证装饰器

@login_required # 登录认证装饰器
def index(request):
    # print(request.user)
    # print(request.user.username)
    # print(request.user.id)
    # print(request.user.is_anonymous)
    #
    # if not request.user.is_authenticated:  # 自己写的登录认证代码
    #     return redirect('/login/')

    return render(request, 'index.html')


@login_required  # 登录认证装饰器
def order(request):
    # 有了登录认证装饰器,就省去了,自己写认证代码.
    # if not request.user.is_authenticated:  # 自己写的登录认证代码
    #     return redirect('/login/')
    return render(request, 'order.html')
def login(request):

    if request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')

        user = auth.authenticate(username=user, password=pwd)
        if user:
            auth.login(request, user)
            next_url = request.GET.get('next', '/index/')  # 获取地址栏中next后面的路径, 注意看下图
            return redirect(next_url)

    return render(request, 'login.html')

在地址栏输入http://127.0.0.1:8000/lorder/因为没有登陆,所以地址栏变成了http://127.0.0.1:8000/login/?next=/order/如下图.next=/order/的意思是登录后跳转到的网址

 

 123.2 完整代码.注意setting.py中添加LOGIN_URL = '/login/'  模板文件基本未变.

from django.shortcuts import render, redirect, HttpResponse
from django.contrib import auth
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required  # 认证装饰器

def login(request):

    if request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')

        user = auth.authenticate(username=user, password=pwd)
        if user:
            auth.login(request, user)
            next_url = request.GET.get('next', '/index/')  # 获取地址栏中next后面的路径
            return redirect(next_url)

    return render(request, 'login.html')


@login_required # 登录认证装饰器
def index(request):
    # print(request.user)
    # print(request.user.username)
    # print(request.user.id)
    # print(request.user.is_anonymous)
    #
    # if not request.user.is_authenticated:  # 自己写的登录认证代码
    #     return redirect('/login/')

    return render(request, 'index.html')


def logout(request):

    auth.logout(request)  # 注销会删除session表中的记录

    return redirect('/login/')


def reg(request):
    if request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')

        # create_user创建普通用户
        # User.objects.create(username=user, password=pwd) 不能用create因为password是需要加密的
        User.objects.create_user(username=user, password=pwd)  # 写入用户信息到auth_user表中
        return redirect('/login/')  # 注册成功则跳转到登录页面

    return render(request, 'reg.html')

@login_required  # 登录认证装饰器
def order(request):
    # 有了登录认证装饰器,就省去了,自己写认证代码.
    # if not request.user.is_authenticated:  # 自己写的登录认证代码
    #     return redirect('/login/')
    return render(request, 'order.html')
views.py
"""authDemo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    path('reg/', views.reg),
    path('order/', views.order),
]
urls.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>订单中心</h3>

</body>
</html>
order.html

 

一二四: 中间件的实现流程

参考:https://www.cnblogs.com/yuanchenqi/articles/9036479.html

124.1 Django中默认的中间件, 在settings.py文件中. 中间件事全局的变量.

 

 124.2 中间件的实现流程

 

 

一二五: 中间件的process_request和process_response方法

 125. 1 中间件的实现流程

 

 

 

 

 

 

 125.2 自定义中间件

  在项目中新建自定义中间件文件名my_middlewares.py

  关键代码:

# my_middlewares.py

from django.utils.deprecation import MiddlewareMixin  # 导入中间件类的父类


class CustomerMiddleware1(MiddlewareMixin):

    def process_request(self, request):  # process_request方法是必须要有的, 其可以没有返回值.参数必须要有
        print("CustomerMiddleware1 process_request")

    def process_response(self, request, response):  # 注意它的参数,是必须要有两个的.
        print("CustomerMiddleware1 process_response")
        return response  # 这里必须要有返回值


class CustomerMiddleware2(MiddlewareMixin):

    def process_request(self, request):  # process_request方法是必须要有的, 其可以没有返回值.参数必须要有
        print("CustomerMiddleware2 process_request")

    def process_response(self, request, response):  # 注意它的参数,是必须要有两个的.
        print("CustomerMiddleware2 process_response")
        return response  # 这里必须要有返回值
# views.py中新建了视图

def index_new(request):
    print('index_new')

    return HttpResponse('index_new')

在settings.py中把上面定义的my_middlewares.py中的两个类加入进去.

 

 

 

最终执行效果:再次体验一下中间件的执行过程.

 

 

 

一二六: 中间件之process_view方法

126.1 接上面.如果一个中间件的process_request有返回值,那么将,直接返回回去,下面的中间件不会再执行.如下图所示.

应用场景:比如某个用户没有登录,某个用户访问太过频繁.

class CustomerMiddleware1(MiddlewareMixin):

    def process_request(self, request):
        print("CustomerMiddleware1 process_request")
        return HttpResponse('CustomerMiddleware1 process_request的有返回值')  # 这里增加返回值

    def process_response(self, request, response): 
        print("CustomerMiddleware1 process_response")
        return response

最终输出效果:

 

 

 

 126.2 有了process_view后,的执行顺序,看下图.

 

 

# my_middlewares.py

from django.utils.deprecation import MiddlewareMixin  # 导入中间件类的父类


class CustomerMiddleware1(MiddlewareMixin):

    def process_request(self, request):  # process_request方法是必须要有的, 其可以没有返回值.参数必须要有
        print("CustomerMiddleware1 process_request")

    def process_response(self, request, response):  # 注意它的参数,是必须要有两个的.
        print("CustomerMiddleware1 process_response")
        return response  # 这里必须要有返回值

    def process_view(self, request, callback, callback_ares, callback_kwargs):
        # 参数callback指的是本次路径对应的视图函数,最后面两个参数是视图函数的参数. 也就是说,视图函数可以在这里直接调出执行,而不需要再到视图中去执行.
        print("CustomerMiddleware1 process_view")


class CustomerMiddleware2(MiddlewareMixin):

    def process_request(self, request):  # process_request方法是必须要有的, 其可以没有返回值.参数必须要有
        print("CustomerMiddleware2 process_request")

    def process_response(self, request, response):  # 注意它的参数,是必须要有两个的.
        print("CustomerMiddleware2 process_response")
        return response  # 这里必须要有返回值

    def process_view(self, request, callback, callback_ares, callback_kwargs):
        print("CustomerMiddleware2 process_view")

执行效果:

 

 126.3 process_view有返回值时

    def process_view(self, request, callback, callback_ares, callback_kwargs):
        print("CustomerMiddleware2 process_view")
        # print(callback(callback_ares))  # 调用执行网址路径对应的视图函数
        return HttpResponse("中间件执行process_view的返回值")  # 这里有返回值,则后面的视图函数部分就不会执行了

一二七: 中间件之process_exception方法

当视图函数执行出错时,才执行该方法

def process_exception(self, request, exception):    # 当视图函数执行出错的时候才执行这个.参数exception就是出错的提示.
 print('CustomerMiddleware2 process_exception')

 

一二八: 中间件之应用

128.1 做IP访问频率限制

128.2 URL访问过滤

如果用户访问的是login视图(放过)

如果访问其他视图,需要检测是不是有session认证,已经有了放行,没有返回login,这样就省得在多个视图函数上写装饰器了!

   用中间件全局一次对用户登录进行验证.就不需要对每一个视图函数加装饰器了.

# my_middlewares.py自定义中间件文件

from
django.utils.deprecation import MiddlewareMixin from django.shortcuts import redirect from authDemo.settings import WHITE_LIST # 导入无需用户登录验证的白名单 class AuthMiddleware(MiddlewareMixin): # 用户登录验证中间件 def process_request(self, request): if request.path in WHITE_LIST: # 路径在白名单中则不需要验证 return None if not request.user.is_authenticated: # 是否登录过 return redirect("/login/")
# settings.py中的白名单

WHITE_LIST = ['/login/', '/reg/', '/logout/']  # 白名单中的路径将不会进行登录验证(中间件用)

 

  

 

 

 

 

 




# response.delete_cookie("cookie_key", path='/', domain=name)  # 删除cookies的操作
posted @ 2021-02-05 20:11  蓝蓝的白云天!  阅读(136)  评论(0编辑  收藏  举报