Django学习day12随堂笔记
阅读原文时间:2022年05月12日阅读:1

每日测验

"""
1.什么是cookie和session,你能描述一下它们的由来和工作机制吗(切勿糊弄,敷衍了事)
2.django中如何操作cookie和session,请写出尽量多的操作方法,并针对session的操作方法详细内部发生的事情,django默认的session失效时间是多久(切勿糊弄,敷衍了事)
3.面相对象中的__init__和__new__的区别是什么,利用__new__可以实现什么
4.如何给CBV添加装饰器,列举你所知道的几种方式
"""

内容回顾

  • forms组件源码

    #    入口:form_obj.is_valid()
    
    # 校验字段和钩子函数的执行
    
    # 报错提示 其实可以有两种方式(针对局部钩子函数)
        1.self.add_error()
      2.raise ValidationError()
    
    """
    python源码里面使用最频繁的其实就是反射
    """
  • cookie与session

    # 由于http协议是无状态的
    
    # cookie概念
        服务端设置保存在客户端浏览器上的键值对(只要符合前面的定义都可以叫cookie)
        cookie虽然是服务端设置的但是浏览器可以选择不保存
    
    # session概念
        存储在服务端上的键值对(用来标识当前用户)               需要基于cookie才能工作
      其实大部分的保存状态的实现都需要基于cookie来做
    
    # 在web领域没有绝对的安全
        基本上防御措施都需要程序员自己写代码完善,并且之内完善没法杜绝
  • django操作cookie

    # 需要借助于HttpResponse对象
    
    # 设置cookie
    obj.set_cookie(key,value)
    # 超时时间
    obj.set_cookie(key,value,max_age/expires)
        expires  针对IE需要用这个参数            数字是以秒为单位
    # 加盐
    obj.set_signed_cookie(key,value,salt='盐')
    # 获取
    request.COOKIES.get(key)
    request.get_signed_cookie(key,salt='盐')
    # 删除
    obj.delete_cookie(key)
    
    """
    校验用户是否登陆才能访问视图函数的装饰器
        能够记录用户在没有登陆之前想要访问的页面,登陆之后跳转到对应的页面
        request.path
        request.path_info
        request.get_full_path()
    """
  • django操作session

    """
    1.session是存储在服务端的 django默认情况下是需要借助于django_session表来存储数据 也就意味着如果你想要操作session那么必须先执行数据库迁移命令让django先把django_session表创建出来(no such table:django_session)
    
    2.django默认的session过期时间是14天
    
    3.session存储在服务端 可以有很多地方存储
        1.表
        2.文件
        3.缓存
        4.其他
        ...
    """
    # 设置
    request.session[key] = value
        """
        三件事
        """
    # 获取
    request.session.get(key)
        """
        三件事
        """
    # 删除
    request.session.delete()
    request.session.flush()
    # 设置超时时间
    request.session.set_expiry()
        1.数字                                                            秒数
      2.datetime/timedelta格式                        日期格式
      3.None                                                         参加全局失效策略
      4.0                                                                 窗口关闭即失效
    
    """
    基于session实现用户登陆
    
    有时候如果多个视图函数都需要使用到一些数据的话,你也可以考虑将该数据存储到django_session表中,方便后续的使用
        eg:
            登陆验证码(bbs作业会涉及到)
    """
  • CBV如何添加装饰器

    """
    django针对CBV添加装饰器需要你导入一个模块
    """
    from django.utils.decorators import method_decorator
    
    # 第一种
    class MyCBV(View):
      def get(self,request):
        return HttpResponse()
    
      @method_decorator(login_auth)
         def post(self,request):
        return HttpResponse()
    
    #  第二种
    @method_decorator(login_auth,name='post')
    @method_decorator(index_de,name='get')
    class MyCBV(View):
      def get(self,request):
        return HttpResponse()
     def post(self,request):
    return HttpResponse()
    # 第三种 class MyCBV(View): @method_decorator(login_auth) def dispatch(self,request,*args,**kwargs): """ 看CBV源码可以得出 CBV里面所有的方法在执行之前都需要先经过 dispatch方法(该方法你可以看成是一个分发方法) """ super().dispatch(request,*args,**kwargs) def get(self,request): return HttpResponse()
     def post(self,request):
    return HttpResponse()</code></pre></li>

今日内容概要

  • django中间件

    首先django自带七个中间件,每个中间件都有各自对应的功能

    并且django还支持程序员自定义中间件

    你在用django开发项目的项目的时候,只要是涉及到全局相关的功能都可以使用中间件方便的完成

    • 全局用户身份校验
    • 全局用户权限校验(补充)
    • 全局访问频率校验
  • 基于django中间件一个重要的编程思想(重要)

  • csrf跨站请求伪造

今日内容详细

django中间件

django请求生命周期流程图

"""
django中间件是django的门户
1.请求来的时候需要先经过中间件才能到达真正的django后端
2.响应走的时候最后也需要经过中间件才能发送出去

django自带七个中间件
"""

研究django中间件代码规律
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

class SessionMiddleware(MiddlewareMixin):
    def process_request(self, request):
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
        request.session = self.SessionStore(session_key)
    def process_response(self, request, response):
        return response

class CsrfViewMiddleware(MiddlewareMixin):
      def process_request(self, request):
        csrf_token = self._get_token(request)
        if csrf_token is not None:
            # Use same token next time.
            request.META['CSRF_COOKIE'] = csrf_token
    def process_view(self, request, callback, callback_args, callback_kwargs):
        return self._accept(request)

    def process_response(self, request, response):
        return response

class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        request.user = SimpleLazyObject(lambda: get_user(request))
"""
django支持程序员自定义中间件并且暴露给程序员五个可以自定义的方法
    1.必须掌握
        process_request

        process_response
    2.了解即可
        process_view

        process_template_response

        process_exception
"""

如何自定义中间件

"""
1.在项目名或者应用名下创建一个任意名称的文件夹
2.在该文件夹内创建一个任意名称的py文件
3.在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
    然后在这个类里面就可以自定义五个方法了
    (这五个方法并不是全部都需要书写,用几个写几个)
4.需要将类的路径以字符串的形式注册到配置文件中才能生效
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    '你自己写的中间件的路径1',
    '你自己写的中间件的路径2',
    '你自己写的中间件的路径3',
]

"""
"""
1.必须掌握
        process_request
            1.请求来的时候需要经过每一个中间件里面的process_request方法
            结果的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
            2.如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
            3.如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行
            而是直接原路返回(校验失败不允许访问...)
            process_request方法就是用来做全局相关的所有限制功能

        process_response
            1.响应走的时候需要结果每一个中间件里面的process_response方法
            该方法有两个额外的参数request,response
            2.该方法必须返回一个HttpResponse对象
                1.默认返回的就是形参response
                2.你也可以自己返回自己的
            3.顺序是按照配置文件中注册了的中间件从下往上依次经过
                如果你没有定义的话 直接跳过执行下一个

        研究如果在第一个process_request方法就已经返回了HttpResponse对象,那么响应走的时候是经过所有的中间件里面的process_response还是有其他情况
        是其他情况
            就是会直接走同级别的process_reponse返回

        flask框架也有一个中间件但是它的规律
            只要返回数据了就必须经过所有中间件里面的类似于process_reponse方法

2.了解即可
        process_view
            路由匹配成功之后执行视图函数之前,会自动执行中间件里面的该方法
            顺序是按照配置文件中注册的中间件从上往下的顺序依次执行

        process_template_response
            返回的HttpResponse对象有render属性的时候才会触发
            顺序是按照配置文件中注册了的中间件从下往上依次经过

        process_exception
            当视图函数中出现异常的情况下触发
            顺序是按照配置文件中注册了的中间件从下往上依次经过
"""

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class MyMiddleware1(MiddlewareMixin):
    def process_request(self,request):
        print('我是第一个自定义中间件里面的process_request方法')
        # return HttpResponse('baby!')

    def process_response(self,request,response):
        """
        :param request:
        :param response: 就是django后端返回给浏览器的内容
        :return:
        """
        print('我是第一个自定义中间件里面的process_response方法')
        return response

    def process_view(self,request,view_name,*args,**kwargs):
        print(view_name,args,kwargs)
        print('我是第一个自定义中间件里面的process_view')

    def process_template_response(self,request,response):
        print('我是第一个自定义中间件里面的process_template_response')
        return response

    def process_exception(self,request,exception):
        print('我是第一个中间件里面的process_exception')
        print(exception)

class MyMiddleware2(MiddlewareMixin):
    def process_request(self,request):
        print('我是第二个自定义中间件里面的process_request方法')

    def process_response(self,request,response):
        print('我是第二个自定义中间件里面的process_response方法')
        return response

    def process_view(self,request,view_name,*args,**kwargs):
        print(view_name,args,kwargs)
        print('我是第二个自定义中间件里面的process_view')

    def process_template_response(self,request,response):
        print('我是第二个自定义中间件里面的process_template_response')
        return response

    def process_exception(self,request,exception):
        print('我是第二个中间件里面的process_exception')
        print(exception)

我是第一个自定义中间件里面的process_request方法
我是第二个自定义中间件里面的process_request方法
<function index at 0x0000021E72065310> ((), {}) {}
我是第一个自定义中间件里面的process_view
<function index at 0x0000021E72065310> ((), {}) {}
我是第二个自定义中间件里面的process_view
我是视图函数index
我是第二个自定义中间件里面的process_response方法
我是第一个自定义中间件里面的process_response方法    

csrf跨站请求伪造

"""
钓鱼网站
    我搭建一个跟正规网站一模一样的界面(中国银行)
    用户不小心进入到了我们的网站,用户给某个人打钱
    打钱的操作确确实实是提交给了中国银行的系统,用户的钱也确确实实减少了
    但是唯一不同的时候打钱的账户不是用户想要打的账户变成了一个莫名其妙的账户

大学英语四六级
    考之前需要学生自己网站登陆缴费

内部本质
    我们在钓鱼网站的页面 针对对方账户 只给用户提供一个没有name属性的普通input框
    然后我们在内部隐藏一个已经写好name和value的input框

如何规避上述问题
    csrf跨站请求伪造校验
        网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
        当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果唯一标识不对直接拒绝(403 forbbiden)如果成功则正常执行
"""

如何符合校验

# form表单如何符合校验
<form action="" method="post">
    {% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>target_user:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
</form>

# ajax如何符合校验
// 第一种 利用标签查找获取页面上的随机字符串
{#data:{"username":'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#}
// 第二种 利用模版语法提供的快捷书写
{#data:{"username":'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
// 第三种 通用方式直接拷贝官方写好的js验证代码并引用到自己的html页面上即可,注意引入本地文件的时候不要忘记配置静态文件
data:{"username":'jason'}

{% load static %}
<script src="{% static 'js/mysetup.js' %}"></script>
<script>
    $("#d1").click(function (){
        $.ajax({
            url:'',
            type:'post',
            //第一种 利用标签查找获取页面上的随机字符串
            //data:{"username":"kk",'csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},
            // 第二种 利用模版语法提供的快捷书写
            {#data:{"username":'kk','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
            // 第三种 通用方式直接拷贝js代码并应用到自己的html页面上即可
            data:{"username":'kk'},
            success:function (){

            }
        })
    })
</script>

js验证代码(直接拷贝放在本地就可以)

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});

csrf相关装饰器

"""
1.网站整体都不校验csrf,就单单几个视图函数需要校验
2.网站整体都校验csrf,就单单几个视图函数不校验
"""
from django.views.decorators.csrf import csrf_protect,csrf_exempt
from django.utils.decorators import method_decorator
"""
csrf_protect  需要校验
    针对csrf_protect符合我们之前所学的装饰器的三种玩法
csrf_exempt   忽视校验
    针对csrf_exempt只能给dispatch方法加才有效
"""
# @csrf_exempt
# @csrf_protect
def transfer(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        target_user = request.POST.get('target_user')
        money = request.POST.get('money')
        print('%s给%s转了%s元'%(username,target_user,money))
    return render(request,'transfer.html')

#CBV相关装饰器
from django.views import View

# @method_decorator(csrf_protect,name='post')  # 针对csrf_protect 第二种方式可以
# @method_decorator(csrf_exempt,name='post')  # 针对csrf_exempt 第二种方式不可以
@method_decorator(csrf_exempt,name='dispatch')
class MyCsrfToken(View):
    # @method_decorator(csrf_protect)  # 针对csrf_protect 第三种方式可以
    # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第三种方式可以
    def dispatch(self, request, *args, **kwargs):
        return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)

    def get(self,request):
        return HttpResponse('get')

    # @method_decorator(csrf_protect)  # 针对csrf_protect 第一种方式可以
    # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第一种方式不可以
    def post(self,request):
        return HttpResponse('post')

补充知识点

# 模块:importlib
"""
需求:从a.py中引用b.py的变量
b.py的位置在 myfile文件下
正常思路 from myfile import b
"""
import importlib
res = 'myfile.b'
#这样也就直接可以通过字符串 拿到不同文件夹里面的变量
# 也是setting文件中中间件文件中直接设置字符串就可以拿到路径的奥秘之处
ret = importlib.import_module(res)  # from myfile import b
# 该方法最小只能到py文件名
print(ret)

重要思想

#很有深度 建议直接在项目中看自己是怎么写的
#精髓代码
import settings
import importlib

def send_all(content):
    for path_str in settings.NOTIFY_LIST:  #path_str就是一个个settings里面的字符串 'notify.email.Email',
        module_path,class_name = path_str.rsplit('.',maxsplit=1) #rsplit从右往左切只切一次
        # module_path = 'notify.email'  class_name = 'Email'
        # 1 利用字符串导入模块
        module = importlib.import_module(module_path)  # from notify import email
        # 2 利用反射获取类名
        cls = getattr(module,class_name)  # 拿到真正类的名字:Email、QQ、Wechat
        # 3 生成类的对象
        obj = cls()
        # 4 利用鸭子类型直接调用send方法
        obj.send(content)

作业

今日作业
1.整理今日内容至个人博客或笔记中
2.自己编写参考django中间件实现功能可配置插拔式设计体会编程思想

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章