1.基于django中间件的拷贝思想

需求:实现三种通知功能
#方式一:
#notify.py
def send_email(content):
    print('邮箱通知:%s'% content)

def send_msg(content):
    print('短信通知:%s'% content)

def send_wechat(content):
    print('微信通知:%s'% content)

#start.py
from first.notify import *

def send_all(content):
    send_msg(content)
    send_email(content)
    send_wechat(content)

if __name__ == '__main__':
    send_all('后天是周末')

#方式二:
#lib文件夹
#bbb.py
name='from bbb'

#aaa.py
import importlib
res='lib.bbb'
#利用字符串形式导入模块
md=importlib.import_module(res)  #这句相当于 from lib import bbb
print(md)    #该模块字符串最小单位只能到文件名

#settings.py
NOTIFY_LIST=[
    'notify.email.Email',
    'notify.msg.Msg',
    'notify.qq.Qq',
    'notify.WeChat.WeChat',
]
#start.py
from notify import *
send_all('周末了,哈哈哈哈')

#notify 包文件
#email.py
class Email(object):
    def __init__(self):
        pass

    def send(self,content):
        print('邮件通知:%s'%content)

#msg.py
class Msg(object):
    def __init__(self):
        pass

    def send(self, content):
        print('短信通知:%s' % content)

#qq.py
class Qq(object):
    def __init__(self):
        pass

    def send(self, content):
        print('qq通知:%s' % content)

#wechat.py
class WeChat(object):
    def __init__(self):
        pass

    def send(self, content):
        print('微信通知:%s' % content)

#__init__.py
import settings
import importlib

def send_all(content):
    for path in settings.NOTIFY_LIST:  #拿到一个个的路径字符串 'notify.email.Email'
        module_path,cls_name=path.rsplit('.',maxsplit=1)
        #字符串'notify.email'  类cls_name='Email'
        md=importlib.import_module(module_path)  #from notify import email
        cls=getattr(md,cls_name)   #获取到文件夹中类的名字
        obj=cls()  #产生一个个类对象
        obj.send(content)  #鸭子类型

2.跨站请求伪造csrf

  • 如何实现钓鱼网站
    • 你在写form表单的时候 让用户填写的账户input并没有name属性,是你自己在内部偷偷隐藏了一个具有name属性的input框,并且value值是你自己的账户,然后将该标签隐藏了
  • 模拟该现象的产生 创建两个django项目
#正经网站
#transfer.py
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')
#transfer.html
<p>这是正经网站</p>
<form action="" method="post">
    <p>username:<input type="text" name="username"></p>
    <p>target_account:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">


#钓鱼网站
#transfer.py
def transfer(request):
    return render(request,'transfer.html')

#transfer.html
<p>这是假冒的网站</p>
<form action="http://127.0.0.1:8000/transfer/" method="post">
    <p>username:<input type="text" name="username"></p>
    <p>target_account:
        <input type="text">
        <input type="text" name="target_user" value="ldd" style="display: none"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
  • 如何解决钓鱼网站这种问题:只处理本网站提供的数据
  • 那么如何判断当前请求是本网站发出的呢?
    • 解决方法:网站在返回给用户一个form表单的时候 会自动在该表单隐藏一个input框,这个框

的value是一个随机字符串 但是网站能够记住每一个浏览器发送的随机字符串

以后在写form表单的时候 只需要在表单中写一个{% csrf_token %}
<p>这是正经网站</p>
<form action="" method="post">
    {% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>target_account:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
  • 为了防止钓鱼网站恶意拦截,正常网站都只要接收到post请求,都会做csrf校验

3.ajax的post请求如何用csrf解决

  • 方式一:较为繁琐
    • 先在页面任意位置上书写{% csrf_token %}
    • 然后在发送ajax请求的时候 通过标签查找获取随机字符串,添加到data自定义对象即可
  • 方式二:较为简单
  • 方式三:官网提供的文件 最通用的一种方式,用于前后端分离
    • 直接新建js文件,放在static文件夹里,记得settings里面配一下。拷贝代码 导入即可
    • 不需要做任何的csrf相关的代码书写
{% csrf_token %}
<button id="d1">发送ajax</button>

<script src="/static/setup.js"></script>  //js文件相关
<script>
    $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            // 第一种
            data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
            // 第二种
            data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
            // 第三种  利用脚本文件
            data:{'username':'jason'},
            success:function (data) {
                alert(data)
            }
        })
    })
</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 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');

将这些代码的文件配置到你的Django项目的静态文件中,在html页面上通过导入该文件即可自动帮我们解决ajax提交post数据时校验csrf_token的问题,(导入该配置文件之前,需要先导入jQuery,因为这个配置文件内的内容是基于jQuery来实现的)

4.csrf相关的装饰器

from django.views.decorators.csrf import csrf_exempt,csrf_protect
# @csrf_exempt  # 不校验 csrf
def index(request):
    return HttpResponse('index')


@csrf_protect  # 校验
def login(request):
    return HttpResponse('login')
  • 这两个装饰器在CBV上有何异同
# @method_decorator(csrf_exempt,name='post')  # csrf_exempt不支持该方法
@method_decorator(csrf_exempt,name='dispatch')  # csrf_exempt
class MyIndex(views.View):
    # @method_decorator(csrf_exempt)  # 可以
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def get(self,request):
        return render(request,'transfer.html')
    # @method_decorator(csrf_exempt,name='post')  # csrf_exempt不支持该方法
    def post(self,request):
        return HttpResponse('OK')
    # csrf_exempt这个装饰器只能给dispatch装才能生效

    """
    csrf_protect方式全都可以  跟你普通的装饰器装饰CBV一致
    """
    # @method_decorator(csrf_protect,name='post')  # 可以
    class MyIndex(views.View):
        @method_decorator(csrf_protect)
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request,*args,**kwargs)
        def get(self,request):
            return render(request,'transfer.html')
        # @method_decorator(csrf_protect)  # 可以
        def post(self,request):
            return HttpResponse('OK')

5.django源码剖析

  • django有两个配置文件,一个是暴露给用户可以配置的,一个是内部全局的(用户配置了就用用户的,用户没有配置就用自己的)
  • 先加载全局配置 给对象设值;然后加载局部配置 再给对象设值;一旦有重复的项,后者覆盖前者。
from django.conf import global_settings
from django.conf import settings

6.auth模块

  • 使用auth模块的时候,要用就用它的全套

  • 如何创建超级用户(root)

python manage.py createsuperuser
  • auth模块常用方法:
1.创建用户
from django.contrib.auth.models import User
# User.objects.create(username=username,password=password)  # 不可用  密码不是加密的
# User.objects.create_user(username=username,password=password)  # 创建普通用户    密码自动加密
#User.objects.create_superuser(username=username,password=password,email='123@qq.com')  # 创建超级用户   需要邮箱数据
2.校验用户名和密码是否正确
from django.contrib import auth
user_obj = auth.authenticate(request,username=username,password=password)
# 必须传用户名和密码两个参数缺一不能
3.保存用户登录状态
auth.login(request,user_obj)
# 只要这句话执行了 后面在任意位置 只要你能拿到request你就可以通过request.user获取到当前登录的用户对象
4.判断当前用户是否登录
request.user.is_authenticated()
5.校验原密码是否正确
request.user.check_password(old_password)
6.修改密码
request.user.set_password(new_password)
request.user.save()  # 千万不要忘了
7.注销
auth.logout(request)
8.校验用户是否登录装饰器
from django.contrib.auth.decorators import login_required
局部配置
@login_required(login_url='/login/')
def index(request):
    pass
全局配置
settings配置文件中 直接配置
LOGIN_URL = '/login/'
@login_required
def index(request):
    pass
# 如果全局配置了 局部也配置  以局部的为准

7.扩展auth_user表字段

    方式1
    利用一对一外键字段关系
    class UserDetail(models.Model):
        phone = models.BigIntegerField()
        user = models.OneToOneField(to='User')

    方式2
    利用继承关系
    from django.contrib.auth.models import AbstractUser
    class Userinfo(AbstractUser):
        phone = models.BigIntegerField()
        register_time = models.DateField(auto_now_add=True)

        # 一定要注意 还需要去配置文件中配置
        AUTH_USER_MODEL = 'app01.Userinfo'  # 应用名.表名
        #之前所有的auth模块功能也全适用于扩展好的表 
12-20 23:57
查看更多