[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)