• 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表还可以当做一个临时的仓库

  • 相关阅读:
    Ural1387 Vasya's Dad
    SGU481 Hero of Our Time
    sjtu1590 强迫症
    sjtu1591 Count On Tree
    sjtu1585 oil
    sjtu1364 countcountcount
    sjtu1333 函数时代
    Fabric-ca client端初始化过程源码分析
    Fabric-ca server端与client端交互
    Fabric-ca server端初始化过程源码分析
  • 原文地址:https://www.cnblogs.com/godlover/p/12193103.html
Copyright © 2020-2023  润新知