importlib模块
#bbb.py
name='from bbb'
#aaa.py
import importlib
res = 'lib.bbb'
# 利用字符串的形式导入模块
md = importlib.import_module(res) # from lib import bbb
print(md) # 该模块字符串最小单位只能到文件名
# <module 'lib.bbb' from 'D:\pycharm\前端\untitled\import_idea\lib\bbb.py'>
print(md.name) # from bbb
基于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 初级思想.notify import *
def send_all(content):
send_msg(content)
send_email(content)
send_wechat(content)
if __name__ == '__main__':
send_all('再坚持一天就周末了')
模仿django
# notify email.py
class Email(object):
def __init__(self):
pass #发送邮件需要的前期准备
def send(self,content):
print('邮件通知:%s'%content)
#notify msg.py
class Msg(object):
def __init__(self):
pass # 发送短信需要的前期准备
def send(self, content):
print('短信通知:%s' % content)
#settings.py
NOTIFY_LIST=[
'notify.email.Email',
'notify.msg.Msg',
'notify.wechat.WeChat',
'notify.qq.Qq',
]
# notify __init__.py
import importlib
import settings
def send_all(content):
for path in settings.NOTIFY_LIST:#'notify.msg.Msg',
module_path,cls_name=path.rsplit('.',maxsplit=1)#module_path='notify.msg' cls_name='Msg'
md=importlib.import_module(module_path)#from notify import email
cls=getattr(md,cls_name)#通过反射 获取到文件中类的名字
obj=cls()#实例化一个个类的对象
obj.send(content)
# start.py
from notify import *
send_all('好嗨哟')
跨站请求伪造csrf
钓鱼网站为例:
写一个跟中国正规网站一模一样的页面,用户输入用户名,密码,对方账户,转账金额,提交。请求确实是朝中国银行发送的,钱也扣了,但是对方账户变了,变成了钓鱼网站提前设置好的账户
实现:
在写form表单的时候,让用户填写对方账户input框没有name属性,而是你自己在内部偷偷隐藏了一个具有name属性的input框,并且value值是自己的账户,然后将这个标签隐藏起来
模拟该现象的产生:创建两个django项目
解决该问题:
只处理本网站发送的post请求
form表单 csrf_token
<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">
</form>
在前端显示的是:
<input type="hidden" name="csrfmiddlewaretoken" value="rJ47FeK9T55wavvVJGY6UxdM1kTMHhTqotGfaXjXIK8Ahz2Uvs02yR9T8bBn5q2D">
ajax csrf_token
方式一
较为繁琐
先在页面任意的位置书写{% csrf_token %},然后再发送ajax请求的时候,通过标签查找获取随机字符串添加到data自定义对象即可
{% csrf_token %}
<button id="d1">点击发送ajax</button>
<script>
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
success:function (data) {
alert(data)
}
})
})
</script>
方式二
较为简单
{% csrf_token %}
<button id="d1">点击发送ajax</button>
<script>
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
success:function (data) {
alert(data)
}
})
})
</script>
方式三
官网提供的文件,是最通用的一种方式,直接新建js文件拷贝代码,导入即可。不需要写任何的csrf相关的代码。
在static里新建一个js文件,再在settings里配置static
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);
}
}
});
在html导入即可
{% csrf_token %}
<button id="d1">点击发送ajax</button>
<script src="/static/setup.js"></script>
<script>
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
data:{'username':'jason'},
success:function (data) {
alert(data)
}
})
})
</script>
csrf相关的装饰器
csrf_exempt 不校验
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt #不校验
def index(request):
return HttpResponse('index')
csrf_protect 校验
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_protect #校验
def login(request):
return HttpResponse('login')
csrf装饰器在CBV上的特例
csrf_exempt 不校验
csrf_exempt 这个装饰器只能给dispatch装才能生效
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django import views
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt,name='dispatch')
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')
def post(self,request):
return HttpResponse('OK')
csrf_protect 校验
csrf_protect 方式全部都可以,在哪里都会生效,和普通装饰器装饰CBV一致
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django import views
from django.utils.decorators import method_decorator
@method_decorator(csrf_protect,name='dispatch')
class MyIndex(views.View):
# @method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
# @method_decorator(csrf_protect)
def get(self,request):
return render(request,'transfer.html')
# @method_decorator(csrf_protect)
def post(self,request):
return HttpResponse('OK')
django settings源码剖析
django有两个配置文件
一个是暴露给用户可以设置的
一个是内部全局的(用户配置了就用用户的,用户没有配置就用自己的)
先加载全局配置,给对象设置。然后再加载局部配置,再给对象设置。一旦有重复的项,后者覆盖前者。
django auth模块
在使用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
use_obj=auth.authenticate(request,username=username,password=password)#自动给你加密密码 然后去数据库校验,request可以不写
必须传用户名和密码 缺一不可
3.保存用户登录状态
auth.login(request,use_obj)
'''只要执行了这句话,之后在任意位置通过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_required(login_url='/lgg/')
全局配置
#settings配置文件中直接配置
LOGIN_URL='/login/'
@login_required
扩展auth_user表字段
方式一
利用一对一外键字段关系
class UserDetail(models.Model):
phone = models.BigIntegerField()
user = models.OneToOneField(to='User')
方式二
利用继承关系
一定要注意 要去配置文件配置
AUTH_USER_MODEL='app01.Userinfo' #应用名.表名
这么写完之后,之前所有的auth模块功能全都以建的表为准
from django.contrib.auth.models import AbstractUser
class Userinfo(AbstractUser):
phone=models.BigIntegerField()
register_time=models.DateField(auto_now_add=True)
基于配置文件的编程思想
基于django settings源码实现自己项目配置文件插拔式设计
#lib conf __init__
import importlib
from lib.conf import global_settings
import os
class Settings(object):
def __init__(self):
for name in dir(global_settings):
if name.isupper():
setattr(self,name,getattr(global_settings,name))
#获取暴露给用户的配置文件字符串路径
module_path=os.environ.get('xxx')
md=importlib.import_module(module_path)
for name in dir(md):
if name.isupper():
k=name
v=getattr(md,name)
setattr(self,k,v)
setting=Settings()
#lib conf global_settings
NAME = '我是暴露给用户的自定义配置'
#conf settings
NAME ='我是暴露给用户的自定义配置'
#start
import os
import sys
BASE_DIR = os.path.dirname(__file__)
sys.path.append(BASE_DIR)
if __name__ == '__main__':
os.environ['xxx']='conf.settings'
from lib.conf import settings
print(settings.NAME)