[TOC]html
通知功能: 邮件, 短信, 微信python
import importlib res = 'lib_test.test' # 正常导入模块 # from lib_test import test # print(test) # <module 'lib_test.test' from '...'> # 利用字符串的形式导入模块, 该字符串最小单位到文件名, 不能到文件里的变量名 md = importlib.import_module(res) print(md) # <module 'lib_test.test' from '...'>
notify(Package): init.py, email.py, msg.py, wechat.pyajax
以后新加功能或是删除功能只须要在NOTIFY_LIST中操做对应的字符串便可数据库
''' settings.py: NOTIFY_LIST = [ 'notify.email.Email', 'notify.msg.Msg', 'notify.wechat.WeChat', ] __init__.py: import settings import importlib def send_all(content): for path_name in settings.NOTIFY_LIST: md_name, cls_name = path_name.rsplit('.', maxsplit=1) # 从右开始以"."开始切割字符串, 只切割一次 md = importlib.import_module(md_name) # 以email为例, 经过字符串导入notify.email cls = getattr(md, cls_name) # 经过类名获取notify.email中的Email obj = cls() obj.send(content) start.py: from notify import * send_all('开始放假啦!') '''
建立两个django项目, 一个为正规网站的服务器, 一个为钓鱼网站的服务器django
''' dj fake views.py def transfer(request): return render(request, 'transfer.html') transfer.html <form action="http://127.0.0.1:8000/transfer/" method="post"> # 将用户输入的信息朝正规网站接口发送 ... <p> target_account: <input type="text"> <input type="text" name="target_account" value="jason" style="display: none"> </p> ... </form> '''
只处理同一个浏览器发出的POST请求,后端
关键: 判断post请求是否为同一浏览器发出的浏览器
解决方法:服务器
<input type="hidden" name="csrfmiddlewaretoken" value="...">
CsrfViewMiddleware: 校验浏览器POST请求中csrfmiddlewaretoken的中间件微信
{% csrf_token %}
, 浏览器在渲染HTML模板时会在对应位置作处理csrf校验机制: 在提交的post请求数据中校验是否有 key为csrfmiddlewaretoken, value为token加密字符串的数据session
先在页面任意非form表单位置书写{% csrf_token %}
, 在发送ajax请求时, 经过标签查找获取token键值对添加到ajax的data参数中
''' ... $.ajax({ url: '', type: 'post', data: {'username': 'jason', 'csrfmiddlewaretoken': '{{ csrf_token }}'}, success: function (data) { alert(data) } }) ... </script> '''
<script src="{% static 'setup.js' %}"></script>
from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_exempt # 装饰器, 不进行csrf校验 def index(request): return HttpResponse('index') @csrf_protect # 装饰器, 进行csrf校验 def login(request): return HttpResponse('login')
csrf_protect装饰器对于cbv的三种装饰方式都适用
csrf_exempt装饰器只能给dispatch函数装才能生效
from django import views from django.utils.decorators import method_decorator # @method_decorator(csrf_exempt, name='post') # 不支持 class MyIndex(views.View): @method_decorator(csrf_exempt, name='dispatch') 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') # 不支持 def post(self, request): return HttpResponse('OK了') ''' urls.py: url(r'^cbv/', views.MyIndex.as_view()) transfer.html: <form action="/cbv/" method="post"> '''
django有两个配置文件:
实现原理:
''' from django.conf import settings from real import settings 1. settings = LazySettings(), 基于模块的单例模式, settings为一个对象 2. os.environ是一个内部全局的大字典, 3. manage.py: os.environ.setdefault("DJANGO_SETTINGS_MODULE", "real.settings"), 给内部全局的大字典设置键值对 4. class LazySettings所在文件中的全局变量: ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE", 5. class LazySettings: settings_module = os.environ.get(ENVIRONMENT_VARIABLE) settings_module为展现给用户的配置文件的路径, '项目名.settings' self._wrapped = Settings(settings_module) 6. class Settings: for setting in dir(global_settings): 获取django内部全局的settings中全部的变量名 if setting.isupper(): # 变量名必须大写 setattr(self, setting, getattr(global_settings, setting)) # self: settings._wrapped对象(组合), 给settings._wrapped对象设置内部全局的settings中的键值对 self.SETTINGS_MODULE = settings_module # '项目名.settings' mod = importlib.import_module(self.SETTINGS_MODULE) # from 项目名 import settings, mod指向展现给用户的配置文件 for setting in dir(mod): # 获取展现给用户的配置文件中全部的变量名 if setting.isupper(): # 变量名必须是大写 setting_value = getattr(mod, setting) # 经过反射获取大写变量名所对应的值 setattr(self, setting, setting_value) # 给settings._wrapped对象设置展现给用户的settings中的键值对 '''
建立超级用户(root): python manage.py createsuperuser
from django.contrib.auth.models import User def register(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # 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') # 建立超级用户, 必需要有邮箱名 return HttpResponse('注册成功!') return render(request, 'register.html')
from django.contrib import auth def log_in(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # res = User.objects.filter(username=username, password=password) # print(res) # <QuerySet []>, 表中密码为密文, 没法直接校验 res = auth.authenticate(request, username=username, password=password) # 自动加密密码, 而后去数据库校验, 必须传两个参数 # print(res) # Dragon, 内部封装好了__str__方法, res实际是一个对象 # print(res.username) # Dragon # print(res.password) # pbk..., 密码对应的密文 if res: # 保存登陆状态, 以前本身保存: request.session['user'] = res.username auth.login(request, res) # 执行后能够在后端任意位置经过request.user获取当前登陆用户对象 return HttpResponse('登陆成功!') return render(request, 'log_in.html') def get_user(request): print(request.user, type(request.user)) # Dragon, <class 'django.utils.functional.SimpleLazyObject'>, 未登陆: AnonymousUser, 匿名用户 print(request.user.is_authenticated()) # True/False, 判断当前用户是否登陆 return HttpResponse('OK!')
from django.contrib.auth.decorators import login_required # 导入登陆认证装饰器 # @login_required(login_url='/log_in/') # 局部配置登陆认证装饰器, login_url参数为用户未登陆时的跳转页面 @login_required # 全局配置登陆认证装饰器: settings.py-->LOGIN_URL = '/log_in/', 若是局部和全局都配置了以局部为准 def change_password(request): user_obj = request.user # 通过登陆认证装饰器后, user_obj确定不为空 if request.method == 'POST': old_password = request.POST.get('old_password') # 防止登陆后其余人修改密码 new_password = request.POST.get('new_password') is_right = request.user.check_password(old_password) # check_password: 校验密码 if is_right: request.user.set_password(new_password) # set_password: 设置新密码 request.user.save() # 修改后须要保存 return render(request, 'change_password.html', locals())
会删除django_session表中的对应记录
@login_required def logout(request): # 本身删: request.session.flush() auth.logout(request) return HttpResponse('注销成功!')
from django.db import models from django.contrib.auth.models import User, AbstractUser # 方式一: 经过外键字段作一对一扩展 class UserDetail(models.Model): phone = models.BigIntegerField() user = models.OneToOneField(to='User') # 方式二: 经过继承 + settings.py-->AUTH_USER_MODEL = 'app01.UserInfo' # 应用名.表名(类名) 扩展 class UserInfo(AbstractUser): phone = models.BigIntegerField() # 扩展字段不能和原auth_user表中的原字段重复 register_time = models.DateField(auto_now_add=True) # 方式二扩展字段后, auth模块全部功能仍可使用, 而且以自定义的表为准
''' 目录: about_django_settings(python项目) conf settings.py lib conf __init__.py global_setings.py start.py ''' # settings.py: NAME = '展现给用户的自定义配置' # global_settings.py: NAME = '项目默认的配置文件' # __init__.py import importlib from lib.conf import global_settings import os class Settings(object): def __init__(self): for setting in dir(global_settings): if setting.isupper(): setattr(self, setting, getattr(global_settings, setting)) module_path = os.environ.get('SETTINGS_MODULE') md = importlib.import_module(module_path) # md == settings for setting in dir(md): if setting.isupper(): setattr(self, setting, getattr(md, setting)) settings = Settings() # start.py import os import sys BASE_DIR = os.path.dirname(__file__) # 把当前项目的根目录添加到环境变量, 使导入语句不会报错, 使用pycharm会自动添加 sys.path.append(BASE_DIR) if __name__ == '__main__': # os.environ.setdefault('SETTINGS_MODULE', 'conf.settings') os.environ['SETTINGS_MODULE'] = 'conf.settings' from lib.conf import settings print(settings.NAME)