Django框架8

时间:2020-01-14
本文章向大家介绍Django框架8,主要包括Django框架8使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Django框架8


forms组件

​ 实现一个小需求:

​ 我们写一个注册页面,获取用户输入的用户民和密码

​ 用户点击注册发送到后端做用户名密码的校验

​ 用户名不可包括尼玛 包含敏感词汇

​ 密码不能为空 密码怎么可以为空

用form表单来实现,提交一次,刷新一次,清空输入框一次

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<form action="" method="post">
    <p>
        用户名:<input type="text" name="username">
        <span style="color: red">{{ error_dict.username }}</span>
    </p>
    <p>密码:<input type="text" name="password">
        <span style="color: red">{{ error_dict.password }}</span>
    </p>
    <p><input type="submit"></p>
</form>

</body>
</html>

后端代码

def register(request):

    error_dict = {}

    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if '尼玛' in username:
            error_dict['username'] = '不可包含敏感词汇'
        if not password:
            error_dict['password'] = '密码怎么可以为空'

    return render(request, 'register.html', locals())

forms组件

​ 1.渲染页面 手写获取用户输入的前端页面代码

​ 2.校验数据 后端获取用户数据并做合法性校验

​ 3.展示信息 将校验之后的结果渲染到前端页面

先创建一个类

from django import forms


class MyRegForm(forms.Form):
    # 用户名最少3位最多六位
    username = forms.CharField(max_length=8, min_length=3)
    password = forms.CharField(max_length=8, min_length=3)
    # email字段必须填写符合邮箱格式的数据
    email = forms.EmailField()

如何去校验数据

三层校验

类中的字段校验

方法中的校验

钩子函数进行校验

点击python console

# 传入待校验的数据 用自己写的类 传入的字典格式的待校验的数据
form_obj = views.MyRegForm({'username':'jason','password':'12','email':'123456'})
# 判断数据是否符合校验规则
form_obj.is_valid()
False
# 如何获取校验之后通过的数据
form_obj.cleaned_data
结果:
{'username': 'jason'}
# 如何获取校验失败的数据
form_obj.errors
结果:
            {
             'password': ['Ensure this value has at least 3 characters (it has 2).'],
             'email': ['Enter a valid email address.']
             }
# forms主键默认的所有的字段都必须传值 传少了一定不行 但是传多了却可以 只校验类里面写的字段 多的自动忽略
form_obj = views.MyRegForm({'username':'jason','password':'123456'})
form_obj.is_vaild()
False
form_obj.errors
结果:
{'email': ['This field is required.']}

form_obj = views.MyRegForm({'username':'jason','password':'123456','email':'123@qq.com','hobby':'adada'})
form_obj.is_vaild()
form_obj.cleaned_data
结果:{'username': 'jason', 'password': '123456', 'email': '123@qq.com'}
form_obj.errors
{}

如何渲染页面

​ 还是需要先写类

class MyRegForm(forms.Form):
    # 用户名最少3位最多8位
    username = forms.CharField(max_lenth=8, min_length=3, label='用户名', error_messages={
        'max_length': '用户名最长8位',
        'min_legth': '用户名最短3位',
        'required': '用户名不能为空'
    },required=False, initial='jason',widget=forms.widgets.TextInput(attrs={'class':'form-control c1 c2'}))
password = forms.CharField(max_length=8, min_length=3, label='密码', widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}))
confirm_password = forms.CharField(max_length=8, min_length=3, label='确认密码', widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}))
# email字段必须填写符合邮箱格式的数据
email = forms.EmailField(label='邮箱', error_messages={
    'required': '邮箱必填',
    'invalid': '邮箱格式不正确'
})
phone = forms.CharField(
validators=[
    RegexValidator(r'^[0-9]+$','请输入数字'),
    RegexValidator(r'^159[0-9]+$','数字必须以159开头')
])

了解其他字段渲染

 gender = forms.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )

    hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()
    )
    hobby1 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )
    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )
    hobby2 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

​ forms组件只帮你渲染获取用户输入(输入 选择 下拉 文件)的标签 不渲染按钮和form表单标签 渲染出来的每一个input提示信息都是类中字段首字母大写

<p>第一种渲染方式:多个p标签 本地测试方便 但是封装程度太高 不便于扩展</p>
三种方式:
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{form_obj.as_table }}

<p>第二种渲染方式: 扩展性较高 书写比较繁琐</p>
<label for='{{ form_obj.username.id_for_label }}'>
{{ form_obj.username.label }}</label>
{{ form_obj.username }}
{{ form_obj.password.label }}{{ form_obj.password }}
{{ form_obj.email.label }}{{ form_obj.email }}

<p>第三种渲染方式 推荐使用</p>
{% for form in form_obj %}
    <p>
        {{ form.label }}{{ form }}
</p>
{% endfor %}
        

如何渲染错误信息

前端

<form action='' method='post' novalidate>
    {% for form in form_obj %}
        <p>
            {{ form.label }}{{ form }}
            <span>{{ form.errors.0 }}</span> # 这个是模板语法 索引不会溢出报错
    </p>
    {% endfor %}
    <input type='submit'>
    
</form>

后端

def reg(request):
    # 首先生成一个空的对象
    form_obj = MyReForm()
    if request.method == 'POST':
        # 获取用户数据并交给forms组件校验 request.POST
        form_obj = MyRegForm(request.POST)
        # 获取校验结果
        if form_obj.is_valid():
            return HttpRespnse('数据没有问题')
        else:
            # 获取校验失败的字段和提示信息
            print(form_obj.errors)
    # 直接将该对象传给前端页面
    return render(request, 'reg.html', locals())

数据校验前后端都要有,但是前端的校验弱不禁风,可有可无,而后端的校验则一定要非常全面

如何取消浏览器自动帮我们校验的功能

form表单取消前端浏览器自动校验功能

<form action='' method='post' novalidate>

常用的参数

label input提示的信息

error_messages 自定义报错的提示信息

required 设置字段是否允许为空

initial 设置默认值

widget 控制type类型及属性 多个类型用空格隔开即可

widget = forms.widgets.TextIput(attrs={ 'class': 'form-control c1 c2' })

widget = forms.widgets.PasswordInput(attrs={'class':'form-control})

钩子函数 (类中的方法)

​ 全局钩子(针对多个字段)

​ 校验密码与确认密码是否一致

​ 局部钩子 (针对单个字段)

​ 校验用户名中不能包含666

全局钩子:实现校验密码与确认密码是否一致

def clean(self):
    # 校验密码与确认密码是否一致
    password = self.cleaned_data.get('password')
    confirm_password = self.cleaned_data.get('confirm_password')
    if not password == confirm_password:
        # 展示信息
        self.add_error('confirm_password','两次密码不一致')
    return self.cleaned_data
        

局部钩子:用户名中不能包含666

def cleaned_username(self):
    username = self.cleaned_data.get('username')
    if '666' in username:
        self.add_error('username','不可含有666')
    return username

如果想要同时操作多个字段的数据就去使用全局钩子

如果先要操作单个字段的数据 就去使用局部钩子

Django操作cookie与session

cookie与session的作用

​ 保存信息

当你第一次登录成功后,服务端会给你返回一个随机字符串,保存客户端浏览器上,之后再次朝服务端发请求,只需要携带该随机字符串,服务端就能识别用户当前的身份

cookie虽然是保存在客户端的浏览器上的,但是是服务器设置的浏览器也是可以拒绝服务器的要求,不保存cookie

cookie

​ 保存在客户端浏览器上的键值对

return HttpResponse(), render(), redirect()
变形
obj = HttpResponse(), render(), redirect()
return obj
设置cookie
    obj.set_cookie()
获取cookie
    request.COOKIES.get()
删除cookie
    obj.delete_cookie()

request.path_info 只拿路径部分 不拿参数

request.path_info: /home/

request.get_full_path 拿路径加参数

request.get_full_path(): /home/?username=jason&password=123

# 装饰器
from functools import wraps


def login_auth(func):
    @wraps(func)
    def inner(request,*args,**kwargs):
        # print('request.path_info:',request.path_info)
        # print('request.get_full_path():',request.get_full_path())
        # 执行被装饰函数之前你可以做的事情
        target_url = request.path_info
        if request.COOKIES.get('username'):
            res = func(request,*args,**kwargs)
            return res
        else:
            return redirect('/login/?next=%s'%target_url)
    return inner
def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'jason' and password == '123':
            # target_url = request.GET.get("next",'/home/')
            target_url = request.GET.get("next")
            # 判断用户登录之前是否有想要访问的url
            if target_url:
                # 保存用户登录状态
                obj = redirect(target_url)
            else:
                obj = redirect('/home/')
            # 设置cookie
            obj.set_cookie('username','jason666',max_age=3)
            return obj
    return render(request,'login.html')

@login_auth
def home(request):
    # 校验浏览器是否有对应的cookie
    # if request.COOKIES.get('username'):
    #     print(request.COOKIES)
    #     return HttpResponse("我是home页面 只有登录的用户才能访问")
    # else:
    #     return redirect('/login/')
    return HttpResponse("我是home页面 只有登录的用户才能访问")

@login_auth
def index(request):
    return HttpResponse('我是index页面 只有登录之后的用户才能看')

@login_auth
def demo(request):
    return HttpResponse('我是demo页面 只有登录之后的用户才能看')

@login_auth
def logout(request):
    obj = HttpResponse('注销了')
    obj.delete_cookie('username')
    return obj

session

​ 保存在服务端上的键值对

​ 设置

​ request.session['key'] = value

​ 1.django内部会自动生成一个随机字符串

​ 2.去django_session表中存储数据 键就是随机字符串 值是要保存的数据(由中间件来做)

​ 3.将生成好的随机字符串返回给客户端浏览器,浏览器保存键值对

​ sessionid 随机字符串

​ 获取

​ request.session.get('key')

​ 1.django会自动去浏览器的cookie查找sessionid键值对,获取随机字符串

​ 2.拿着该随机字符串去django_session表中比对数据

​ 3.如果比对上了 就将随机字符串对应的数据获取出来并封装到

request.session提供用户调用

djang中默认的session超时时间为14天

设置会话session,cookie的超时时间

request.session.set_expiry(value)

​ 如果value是个整数,session会在这些秒以后失效

​ 如果value是个datatime或timedelta,session就会在这个时间后失效

​ 如果value是0,用户关闭浏览器session就后悔失效

​ 如果value是None,session会依赖全局session失效策略

删除当前会话的所有session数据

request.session.delete()

删除当前会话的数据,并删除会话的cookie 推荐使用

request.sesson.flush()

​ 这用于确保前面的会话数据不可以再次被用户的浏览器访问,例如,django.contrib.auth.logout() 函数中就会调用它

django_session表还可以当做一个临时的仓库

原文地址:https://www.cnblogs.com/godlover/p/12193103.html