目錄html
1.大而全的一個web框架 採用的是MVT模式 入手簡單 2.Django的賣點是超高的開發效率,其性能擴展有限;採用Django的項目,在流量達到必定規模後,都須要對其進行重構,才能知足性能的要求。 3.Django中的ORM很是方便,作簡單的對象定義,它就能自動生成數據庫結構、以及全功能的管理後臺。 4.Django內置的ORM跟框架內的其餘模塊耦合程度高。應用程序必須使用Django內置的ORM, 5.Django適用的是中小型的網站,或者是做爲大型網站快速實現產品雛形的工具。 Django模板的設計哲學是完全的將代碼、樣式分離; Django從根本上杜絕在模板中進行編碼、處理數據的可能
用戶請求進來先走到 wsgi 而後將請求交給 jango的中間件 穿過django中間件(方法是process_request) 接着就是 路由匹配 路由匹配成功以後就執行相應的 視圖函數 在視圖函數中能夠調用orm作數據庫操做 再從模板路徑 將模板拿到 而後在後臺進行模板渲染 模板渲染完成以後就變成一個字符串 再把這個字符串通過全部中間件(方法:process_response) 和wsgi 返回給用戶
MVC:model 模型、view(視圖)、controller(控制器) MTV:model、tempalte、view
.Admin是對model中對應的數據表進行增刪改查提供的組件 .model組件:負責操做數據庫 .form組件:1.生成HTML代碼2.數據有效性校驗3校驗信息返回並展現 .ModelForm組件即用於數據庫操做,也可用於用戶請求的驗證
當請求一個頁面時, Django會創建一個包含請求元數據的 HttpRequest 對象. 當Django 加載對應的視圖時, HttpRequest對象將做爲視圖函數的第一個參數. 每一個視圖會返回一個HttpResponse對象.
websocket是給瀏覽器新建的一套(相似與http)協議,協議規定:(\r\n分割)瀏覽器和服務器鏈接以後不斷開, 以此完成:服務端向客戶端主動推送消息。 websocket協議額外作的一些操做 握手 ----> 鏈接錢進行校驗 加密 ----> payload_len=127/126/<=125 --> mask key 本質 建立一個鏈接後不斷開的socket 當鏈接成功以後: 客戶端(瀏覽器)會自動向服務端發送消息,包含: Sec-WebSocket-Key: iyRe1KMHi4S4QXzcoboMmw== 服務端接收以後,會對於該數據進行加密:base64(sha1(swk + magic_string)) 構造響應頭: HTTP/1.1 101 Switching Protocols\r\n Upgrade:websocket\r\n Connection: Upgrade\r\n Sec-WebSocket-Accept: 加密後的值\r\n WebSocket-Location: ws://127.0.0.1:8002\r\n\r\n 發給客戶端(瀏覽器) 創建:雙工通道,接下來就能夠進行收發數據 發送數據是加密,解密,根據payload_len的值進行處理 payload_len <= 125 payload_len == 126 payload_len == 127 獲取內容: mask_key 數據 根據mask_key和數據進行位運算,就能夠把值解析出來。
客戶端向服務端發送消息時,會有一個'sec-websocket-key'和'magic string'的隨機字符串(魔法字符串) # 服務端接收到消息後會把他們鏈接成一個新的key串,進行編碼、加密,確保信息的安全性
django 大而全的框架它的內部組件比較多,內部提供:ORM、Admin、中間件、Form、ModelForm、Session、 緩存、信號、CSRF;功能也都挺完善的 flask ,微型框架,內部組件就比較少了,可是有不少第三方組件來擴展它, 好比說有那個wtform(與django的modelform相似,表單驗證)、flask-sqlalchemy(操做數據庫的)、 flask-session、flask-migrate、flask-script、blinker可擴展強,第三方組件豐富。因此對他自己來講有那種短小精悍的感受 - tornado,異步非阻塞。 django和flask的共同點就是,他們2個框架都沒有寫socket,因此他們都是利用第三方模塊wsgi。 可是內部使用的wsgi也是有些不一樣的:django自己運行起來使用wsgiref,而flask使用werkzeug wsgi 還有一個區別就是他們的請求管理不太同樣:django是經過將請求封裝成request對象,再經過參數傳遞,而flask是經過上下文管理機制 Tornado 是一個輕量級的Web框架,異步非阻塞+內置WebSocket功能。 '目標':經過一個線程處理N個併發請求(處理IO)。 內部組件 #內部本身實現socket #路由系統 #視圖 #模板 #cookie #csrf
django中能夠經過channel實現websocket
jango中提供了6種緩存方式: 開發調試(不加緩存) 內存 文件 數據庫 Memcache緩存(python-memcached模塊) Memcache緩存(pylibmc模塊) 安裝第三方組件支持redis: django-redis組件 設置緩存 # 全站緩存(中間件) MIDDLEWARE_CLASSES = ( ‘django.middleware.cache.UpdateCacheMiddleware’, #第一 'django.middleware.common.CommonMiddleware', ‘django.middleware.cache.FetchFromCacheMiddleware’, #最後 ) # 視圖緩存 from django.views.decorators.cache import cache_page import time @cache_page(15) #超時時間爲15秒 def index(request): t=time.time() #獲取當前時間 return render(request,"index.html",locals()) # 模板緩存 {% load cache %} <h3 style="color: green">不緩存:-----{{ t }}</h3> {% cache 2 'name' %} # 存的key <h3>緩存:-----:{{ t }}</h3> {% endcache %}
pip install django-redis apt-get install redis-serv 在setting添加配置文件 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", # 緩存類型 "LOCATION": "127.0.0.1:6379", # ip端口 "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", # "CONNECTION_POOL_KWARGS": {"max_connections": 100} # 鏈接池最大鏈接數 # "PASSWORD": "密碼", } } } 使用 from django.shortcuts import render,HttpResponse from django_redis import get_redis_connection def index(request): # 根據名字去鏈接池中獲取鏈接 conn = get_redis_connection("default") conn.hset('n1','k1','v1') # 存數據 return HttpResponse('...')
同源:域名、協議、端口徹底相同。 跨域:域名、協議、端口有其中的同樣不一樣。 什麼是同源策略 同協議、同domain(或ip)、同端口,視爲同一個域,一個域內的腳本僅僅具備本域內的權限。 理解:本域腳本只能讀寫本域內的資源,而沒法訪問其它域的資源。這種安全限制稱爲同源策略。 前端解決跨域訪問的經常使用方式 1.jsonp 2.iframe 元素會建立包含另一個文檔的內聯框架(即行內框架) 3.代理:如vue-cli項目中的config/index.js文件中的proxyTable設置所要跨域訪問的地址 ors跨域(場景:先後端分離時,本地測試開發時使用) 若是網站之間存在跨域,域名不一樣,端口不一樣會致使出現跨域,但凡出現跨域,瀏覽器就會出現同源策略的限制 解決:在咱們的服務端給咱們響應數據,加上響應頭---> 在中間件加的 設想這樣一種狀況:A網站是一家銀行,用戶登陸之後,又去瀏覽其餘網站。若是其餘網站能夠讀取A網站的 Cookie,會發生什麼? 很顯然,若是 Cookie 包含隱私(好比存款總額),這些信息就會泄漏。更可怕的是,Cookie 每每用來保存用戶的登陸狀態,若是用戶沒有退出登陸,其餘網站就能夠冒充用戶,隨心所欲。由於瀏覽器同時還規定,提交表單不受同源政策的限制。 因而可知,"同源政策"是必需的,不然 Cookie 能夠共享,互聯網就毫無安全可言了。 https://www.cnblogs.com/kiscon/p/8633076.html
分類: 1** 信息,服務器收到請求,須要請求者繼續執行操做 2** 成功,操做被成功接收並處理 3** 重定向,須要進一步的操做以完成請求 4** 客戶端錯誤,請求包含語法錯誤或沒法完成請求 5** 服務器錯誤,服務器在處理請求的過程當中發生了錯誤 常見的狀態碼 200 -請求成功 202 -已接受請求,還沒有處理 204 -請求成功,且不需返回內容 301 - 資源(網頁等)被永久轉移到其餘url 400 - 請求的語義或是參數有錯 403 - 服務器拒絕請求 404 - 請求資源(網頁)不存在 500 - 內部服務器錯誤 502 - 網關錯誤,通常是服務器壓力過大致使鏈接超時 503 - 因爲超載或系統維護,服務器暫時的沒法處理客戶端的請求。
- user-agent這個頭信息識別發出請求的瀏覽器或其餘客戶端,並能夠向不一樣類型的瀏覽器返回不一樣的內容。 - host這個頭信息指定原始的 URL 中的主機和端口。 - referer 這個頭信息指示所指向的 Web 頁的 URL。例如,若是您在網頁 1,點擊一個連接到網頁 2,當瀏覽器請求網頁 2 時,網頁 1 的 URL 就會包含在 Referer 頭信息中。 - cookie 這個頭信息把以前發送到瀏覽器的 cookies 返回到服務器。 - content-type
#Http: 80端口 #https: 443端口 # http信息是明文傳輸,https則是具備安全性的ssl加密傳輸協議。 #- 自定義證書 - 服務端:建立一對證書 - 客戶端:必須攜帶證書 #- 購買證書 - 服務端: 建立一對證書,。。。。 - 客戶端: 去機構獲取證書,數據加密後發給我們的服務單 - 證書機構:公鑰給改機構
WSGI: web服務器網關接口,是一套協議。用於接收用戶請求並將請求進行初次封裝,而後將請求交給web框架 實現wsgi協議的模塊: 1. wsgiref,本質上就是編寫一個socket服務端,用於接收用戶請求(django) 2.werkzeug,本質上就是編寫一個socket服務端,用於接收用戶請求(flask) uwsgi: 與WSGI同樣是一種通訊協議,它是uWSGI服務器的獨佔協議,用於定義傳輸信息的類型 uWSGI: 是一個web服務器,實現了WSGI協議,uWSGI協議,http協議,
process_request : 請求進來時,權限認證 process_view : 路由匹配以後,可以獲得視圖函數 process_exception : 異常時執行 process_template_responseprocess : 模板渲染時執行 process_response : 請求有響應時執行
反向解析路由字符串 路由系統中name的做用:反向解析 url(r'^home', views.home, name='home') 在模板中使用:{ % url 'home' %} 在視圖中使用:reverse(「home」) 當後期要修改url設置規則時,在不使用name字段的時候,不但要修改urls.py文件中的url路由,還要講html文件中全部的相同路徑進行修改,在實際應用中將會有大量的url路由,這樣修改下來將會十分的麻煩。 可是,若是使用name字段只須要在urls.py 文件中將path()中的url路由修改了就好了,html文件中的則不須要修改,由於這種方式下是經過name字段來映射url的,故不用再去修改html文件了。而通常狀況下name的值又是不會變化的,故後期修改起來將會十分的方便。
即便不一樣的APP使用相同的URL名稱,URL的命名空間模式也可讓你惟一反轉命名的URL。
FBV和CBV本質是同樣的 基於函數的視圖叫作FBV,基於類的視圖叫作CBV 在python中使用CBV的優勢: cbv的好處 提升了代碼的複用性,可使用面嚮對象的技術,好比Mixin(多繼承) 能夠用不一樣的函數針對不一樣的HTTP方法處理,而不是經過不少 if 判斷,提升代碼可讀性
第一步先引入模塊from django.utils.decorators import method_decorator` 第2步 加語法糖@method_decorator(wrapper)` from django.shortcuts import render,HttpResponse from django.views import View from django.utils.decorators import method_decorator def wrapper(func): def inner(*args, **kwargs): print(11111) ret = func(*args, **kwargs) print(22222) return ret return inner # @method_decorator(wrapper,name='get') # 方式3給get加 用的很少 class LoginView(View): @method_decorator(wrapper) #方式1 def get(self,request): print('小小小小') return HttpResponse('登陸成功') def post(self,request): print(request.POST) return HttpResponse('登陸成功')
- 沒什麼區別,由於他們的本質都是函數。CBV的.as_view()返回的view函數,view函數中調用類的dispatch方法, 在dispatch方法中經過反射執行get/post/delete/put等方法。D 非要說區別的話: - CBV比較簡潔,GET/POST等業務功能分別放在不一樣get/post函數中。FBV本身作判斷進行區分。
request.method ——》 請求的方式 8種 GET POST PUT DELETE OPTIONS request.GET ——》 字典 url上攜帶的參數 request.POST ——》 字典 form表單經過POST請求提交的數據 request.path_info ——》 URL路徑 不帶參數 request.body ——》 請求體 request.FILES 上傳的文件 {} request.COOKIES cookie request.session session request.META 請求頭 redirect 重定向 def cs(request): return redirect('/cs1/') #重定向到url爲cs1的地址 def cs1(request): return HttpResponse('666') #返回字符串666 def cs1(request): render(request,'xx.html')#返回html頁面
返回QuerySet對象的方法有: all()所有 filter()過濾 exclude() 排除的意思 order_by() reverse() queryset類型的數據來調用,對查詢結果反向排序, distinct() values和values_list獲得的queryset類型的數據來調用,從返回結果中剔除重複紀錄 去重 特殊的QuerySet: values() 返回一個可迭代的字典序列 values_list() 返回一個可迭代的元組序列 返回具體對象的: get() first()第一個 last()最後一個 返回布爾值的方法有: exists() queryset類型的數據來調用,若是QuerySet包含數據,就返回True,不然返回False 返回數字的方法有: count() model對象能夠點出來 queryset對象相互轉換 只要是返回的queryset類型,就能夠繼續鏈式調用queryset類型的其餘的查找方法,其餘方法也是同樣的 <1> all(): 查詢全部結果,結果是queryset類型 查詢全部的數據 .all方法 返回的是queryset集合 all_objs = models.Student.objects.all() # 相似於列表 -- queryset集合 for i in all_objs: print(i.name) print(all_objs) <2> filter(**kwargs): 它包含了與所給篩選條件相匹配的對象,結果也是queryset類型 Book.objects.filter(title='linux',price=100) #裏面的多個條件用逗號分開,而且這幾個條件必須都成立,是and的關係, models.Student.objects.all().filter(id=7) queryset類型能夠調用fitler在過濾 <3> get(**kwargs): 返回與所給篩選條件相匹配的對象,不是queryset類型,是行記錄對象,返回結果有且只有一個, 若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。捕獲異常try。 Book.objects.get(id=1) <4> exclude(**kwargs): 排除的意思,它包含了與所給篩選條件不匹配的對象,沒有不等於的操做昂,用這個exclude,返回值是queryset類型 Book.objects.exclude(id=6),返回id不等於6的全部的對象,或者在queryset基礎上調用,Book.objects.all().exclude(id=6) exclude(**kwargs): 排除,objects控制器和queryset集合均可以調用,返回結果是queryset類型 query = models.Student.objects.exclude(id=1) print(query) query = models.Student.objects.filter(age=38).exclude(id=6) print(query) <5> order_by(*field): 排序 queryset類型的數據來調用,對查詢結果排序,默認是按照id來升序排列的,返回值仍是queryset類型 models.Book.objects.all().order_by('price','id') #直接寫price,默認是按照price升序排列,按照字段降序排列,就寫個負號就好了order_by('-cs'),order_by('price','id')是多條件排序,按照price進行升序,price相同的數據,按照id進行升序 <6> reverse(): queryset類型的數據來調用,對查詢結果反向排序,返回值仍是queryset類型 # 只能夠排序以後反轉 # query = models.Student.objects.all().order_by('id').reverse() # print(query) <7> count(): queryset類型的數據來調用,返回數據庫中匹配查詢(QuerySet)的對象數量。 <8> first(): queryset類型的數據來調用 ,返回第一條記錄結果爲model對象類型 Book值 <9> last(): queryset類型的數據來調用,返回最後一條記錄,結果爲model對象類型 <10> exists(): queryset類型的數據來調用,若是QuerySet包含數據,就返回True,不然返回False 空的queryset類型數據也有布爾值True和False,可是通常不用它來判斷數據庫裏面是否是有數據,若是有大量的數據,你用它來判斷,那麼就須要查詢出全部的數據,效率太差了,用count或者exits 例:all_books = models.Book.objects.all().exists() #翻譯成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,就是經過limit 1,取一條來看看是否是有數據 <11> values(*field): 用的比較多,queryset類型的數據來調用,返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列 model的實例化對象,而是一個可迭代的字典序列,只要是返回的queryset類型,就能夠繼續鏈式調用queryset類型的其餘的查找方法,其餘方法也是同樣的。 裏面能夠加子段顯示 <12> values_list(*field): 它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列 裏面能夠加子段顯示 <13> distinct(): values和values_list獲得的queryset類型的數據來調用,從返回結果中剔除重複紀錄 去重,結果仍是queryset 裏面不能夠傳參 顯示nanme等等能夠用來去重 query = models.Student.objects.all().values('age').distinct() print(query)
def filter(self, *args, **kwargs) # 條件查詢(符合條件) # 查出符合條件 # 條件能夠是:參數,字典,Q def exclude(self, *args, **kwargs) # 條件查詢(排除條件) # 排除不想要的 # 條件能夠是:參數,字典,Q
1.使用execute執行自定義的SQL 直接執行SQL語句(相似於pymysql的用法) # 更高靈活度的方式執行原生SQL語句 from django.db import connection cursor = connection.cursor() cursor.execute("SELECT DATE_FORMAT(create_time, '%Y-%m') FROM blog_article;") ret = cursor.fetchall() print(ret) 2.使用extra方法 :queryset.extra(select={"key": "原生的SQL語句"}) 3.使用raw()方法 1.執行原始sql並返回模型 2.依賴model多用於查詢
F:主要用來獲取原數據進行計算。 同表 字段比較 更新) Django 支持 F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操做。 修改操做也可使用F函數,好比將每件商品的價格都在原價格的基礎上增長10 from django.db.models import F from app01.models import Goods Goods.objects.update(price=F("price")+10) # 對於goods表中每件商品的價格都在原價格的基礎上增長10元 F查詢專門對對象中某列值的操做,不可以使用__雙下劃線! Q:用來進行復雜查詢 Q查詢(與或非) Q查詢能夠組合使用 「&」, 「|」 操做符,當一個操做符是用於兩個Q的對象,它產生一個新的Q對象, Q對象能夠用 「~」 操做符放在前面表示否認,也可容許否認與不否認形式的組合。 Q對象能夠與關鍵字參數查詢一塊兒使用,不過必定要把Q對象放在關鍵字參數查詢的前面。 Q(條件1) | Q(條件2) 或 Q(條件1) & Q(條件2) 且 Q(條件1) & ~Q(條件2) 非
def bulk_create(self, objs, batch_size=None): # 批量插入 # batch_size表示一次插入的個數 objs = [ models.DDD(name='r11'), models.DDD(name='r22') ] models.DDD.objects.bulk_create(objs, 10)
def defer(self, *fields): models.UserInfo.objects.defer('username','id') 或 models.UserInfo.objects.filter(...).defer('username','id') #映射中排除某列數據 def only(self, *fields): #僅取某個表中的數據 models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id')
def filter(self, *args, **kwargs) # 條件查詢(符合條件) # 查出符合條件 # 條件能夠是:參數,字典,Q def exclude(self, *args, **kwargs) # 條件查詢(排除條件) # 排除不想要的 # 條件能夠是:參數,字典,Q
方式一:手動使用queryset的using方法 from django.shortcuts import render,HttpResponse from app01 import models def index(request): models.UserType.objects.using('db1').create(title='普通用戶') # 手動指定去某個數據庫取數據 result = models.UserType.objects.all().using('db1') print(result) return HttpResponse('...') 方式二:寫配置文件 class Router1: # 指定到某個數據庫取數據 def db_for_read(self, model, **hints): """ Attempts to read auth models go to auth_db. """ if model._meta.model_name == 'usertype': return 'db1' else: return 'default' # 指定到某個數據庫存數據 def db_for_write(self, model, **hints): """ Attempts to write auth models go to auth_db. """ return 'default' 再寫到配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }, 'db1': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } DATABASE_ROUTERS = ['db_router.Router1',]
def values(self, *fields): # 獲取每行數據爲字典格式 def values_list(self, *fields, **kwargs): # 獲取每行數據爲元祖
obj_list裏面是列表 列表裏有對象 models.Book.objects.bulk_create(obj_list) #批量建立
使用django的信號機制,能夠在添加、刪除數據先後設置日誌記錄 pre_init # Django中的model對象執行其構造方法前,自動觸發 post_init # Django中的model對象執行其構造方法後,自動觸發 pre_save # Django中的model對象保存前,自動觸發 post_save # Django中的model對象保存後,自動觸發 pre_delete # Django中的model對象刪除前,自動觸發 post_delete # Django中的model對象刪除後,自動觸發
db first: 先建立數據庫,再更新表模型 code first:先寫表模型,再更新數據庫 https://www.cnblogs.com/jassin-du/p/8988897.html
一、修改seting文件,在setting裏面設置要鏈接的數據庫類型和名稱、地址 二、運行下面代碼能夠自動生成models模型文件 - python manage.py inspectdb 三、建立一個app執行下下面代碼: - python manage.py inspectdb > app/models.py
SQL: # 優勢: 執行速度快 # 缺點: 編寫複雜,開發效率不高 --------------------------------------------------------------------------- ORM: # 優勢: 讓用戶再也不寫SQL語句,提升開發效率 能夠很方便地引入數據緩存之類的附加功能 # 缺點: 在處理多表聯查、where條件複雜查詢時,ORM的語法會變得複雜。 沒有原生SQL速度快
目的:防止用戶直接向服務端發起POST請求 - 用戶先發送GET獲取csrf token: Form表單中一個隱藏的標籤 + token - 發起POST請求時,須要攜帶以前發送給用戶的csrf token; - 在中間件的process_view方法中進行校驗。 在html中添加{%csrf_token%}標籤
filter : 相似管道,只能接受兩個參數第一個參數是|前的數據 simple_tag : 相似函數 一、模板繼承:{ % extends 'layouts.html' %} 二、自定義方法 'filter':只能傳遞兩個參數,能夠在if、for語句中使用 'simple_tag':能夠無線傳參,不能在if for中使用 'inclusion_tags':可使用模板和後端數據 三、防xss攻擊: '|safe'、'mark_safe'
- 做用: - 對用戶請求數據格式進行校驗 - 自動生成HTML標籤 - 區別: - Form,字段須要本身手寫。 class Form(Form): xx = fields.CharField(.) xx = fields.CharField(.) xx = fields.CharField(.) xx = fields.CharField(.) - ModelForm,能夠經過Meta進行定義 class MForm(ModelForm): class Meta: fields = "__all__" model = UserInfo - 應用:只要是客戶端向服務端發送表單數據時,均可以進行使用,如:用戶登陸註冊
方式一:重寫構造方法,在構造方法中從新去數據庫獲取值 class UserForm(Form): name = fields.CharField(label='用戶名',max_length=32) email = fields.EmailField(label='郵箱') ut_id = fields.ChoiceField( # choices=[(1,'普通用戶'),(2,'IP用戶')] choices=[] ) def __init__(self,*args,**kwargs): super(UserForm,self).__init__(*args,**kwargs) self.fields['ut_id'].choices = models.UserType.objects.all().values_list('id','title') 方式二: ModelChoiceField字段 from django.forms import Form from django.forms import fields from django.forms.models import ModelChoiceField class UserForm(Form): name = fields.CharField(label='用戶名',max_length=32) email = fields.EmailField(label='郵箱') ut_id = ModelChoiceField(queryset=models.UserType.objects.all()) 依賴: class UserType(models.Model): title = models.CharField(max_length=32) def __str__(self): return self.title
在django2.0後,定義外鍵和一對一關係的時候須要加on_delete選項,此參數爲了不兩個表裏的數據不一致問題,否則會報錯: TypeError: __init__() missing 1 required positional argument: 'on_delete' 舉例說明: user=models.OneToOneField(User) owner=models.ForeignKey(UserProfile) 須要改爲: user=models.OneToOneField(User,on_delete=models.CASCADE) --在老版本這個參數(models.CASCADE)是默認值 owner=models.ForeignKey(UserProfile,on_delete=models.CASCADE) --在老版本這個參數(models.CASCADE)是默認值 參數說明: on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五個可選擇的值 CASCADE:此值設置,是級聯刪除。 PROTECT:此值設置,是會報完整性錯誤。 SET_NULL:此值設置,會把外鍵設置爲null,前提是容許爲null。 SET_DEFAULT:此值設置,會把設置爲外鍵的默認值。 SET():此值設置,會調用外面的值,能夠是一個函數。 通常狀況下使用CASCADE就能夠了。
contenttype是django的一個組件(app),它能夠將django下全部app下的表記錄下來 可使用他再加上表中的兩個字段,實現一張表和N張表動態建立FK關係。 - 字段:表名稱 - 字段:數據行ID 應用:路飛表結構優惠券和專題課和學位課關聯
//方式一給每一個ajax都加上上請求頭 function Do1(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', data:{csrfmiddlewaretoken:'{{ csrf_token }}',name:'alex'} success:function(data){ console.log(data); } }); } 方式二:須要先下載jQuery-cookie,才能去cookie中獲取token function Do1(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', headers:{ 'X-CSRFToken':$.cookie('csrftoken') // 去cookie中獲取 }, success:function(data){ console.log(data); } }); } 方式三:搞個函數ajaxSetup,當有多的ajax請求,即會執行這個函數 $.ajaxSetup({ beforeSend:function (xhr,settings) { xhr.setRequestHeader("X-CSRFToken",$.cookie('csrftoken')) } }); 函數版本 <body> <input type="button" onclick="Do1();" value="Do it"/> <input type="button" onclick="Do2();" value="Do it"/> <input type="button" onclick="Do3();" value="Do it"/> <script src="/static/jquery-3.3.1.min.js"></script> <script src="/static/jquery.cookie.js"></script> <script> $.ajaxSetup({ beforeSend: function(xhr, settings) { xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); } }); function Do1(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } function Do2(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } function Do3(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } </script> </body>
vue-resource的interceptors攔截器的做用正是解決此需求的妙方。 在每次http的請求響應以後,若是設置了攔截器以下,會優先執行攔截器函數,獲取響應體,而後纔會決定是否把response返回給then進行接收
一、v-if指令:判斷指令,根據表達式值得真假來插入或刪除相應的值。 二、v-show指令:條件渲染指令,不管返回的布爾值是true仍是false,元素都會存在在html中,只是false的元素會隱藏在html中,並不會刪除. 三、v-else指令:配合v-if或v-else使用。 四、v-for指令:循環指令,至關於遍歷。 五、v-bind:給DOM綁定元素屬性。 六、v-on指令:監聽DOM事件。
restful其實就是一套編寫接口的'協議',規定如何編寫以及如何設置返回值、狀態碼等信息。 # 最顯著的特色: # 用restful: 給用戶一個url,根據method不一樣在後端作不一樣的處理 好比:post建立數據、get獲取數據、put和patch修改數據、delete刪除數據。 # 不用restful: 給調用者不少url,每一個url表明一個功能,好比:add_user/delte_user/edit_user/ # 固然,還有協議其餘的,好比: '版本'來控制讓程序有多個版本共存的狀況,版本能夠放在 url、請求頭(accept/自定義)、GET參數 '狀態碼'200/300/400/500 'url中儘可能使用名詞'restful也能夠稱爲「面向資源編程」 'api標示' api.luffycity.com www.luffycity.com/api/
'一個接口經過1次相同的訪問,再對該接口進行N次相同的訪問時,對資源不造影響就認爲接口具備冪等性。' GET, #第一次獲取結果、第二次也是獲取結果對資源都不會形成影響,冪等。 POST, #第一次新增數據,第二次也會再次新增,非冪等。 PUT, #第一次更新數據,第二次不會再次更新,冪等。 PATCH,#第一次更新數據,第二次不會再次更新,非冪等。 DELTE,#第一次刪除數據,第二次不在再刪除,冪等。
'遠程過程調用協議' 是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。 進化的順序: 現有的RPC,而後有的RESTful規範
# 在編寫接口時能夠不使用django rest framework框架, # 不使用:也能夠作,能夠用django的CBV來實現,開發者編寫的代碼會更多一些。 # 使用:內部幫助咱們提供了不少方便的組件,咱們經過配置就能夠完成相應操做,如: '序列化'能夠作用戶請求數據校驗+queryset對象的序列化稱爲json '解析器'獲取用戶請求數據request.data,會自動根據content-type請求頭的不能對數據進行解析 '分頁'將從數據庫獲取到的數據在頁面進行分頁顯示。 # 還有其餘組件: '認證'、'權限'、'訪問頻率控制
#- 路由,自動幫助開發者快速爲一個視圖建立4個url www.oldboyedu.com/api/v1/student/$ www.oldboyedu.com/api/v1/student(?P<format>\w+)$ www.oldboyedu.com/api/v1/student/(?P<pk>\d+)/$ www.oldboyedu.com/api/v1/student/(?P<pk>\d+)(?P<format>\w+)$ #- 版本處理 - 問題:版本均可以放在那裏? - url - GET - 請求頭 #- 認證 - 問題:認證流程? #- 權限 - 權限是否能夠放在中間件中?以及爲何? #- 訪問頻率的控制 匿名用戶能夠真正的防止?沒法作到真正的訪問頻率控制,只能把小白拒之門外。 若是要封IP,使用防火牆來作。 登陸用戶能夠經過用戶名做爲惟一標示進行控制,若是有人註冊不少帳號,則沒法防止。 #- 視圖 #- 解析器 ,根據Content-Type請求頭對請求體中的數據格式進行處理。request.data #- 分頁 #- 序列化 - 序列化 - source - 定義方法 - 請求數據格式校驗 #- 渲染器
a. 繼承APIView(最原始)但定製性比較強 這個類屬於rest framework中的頂層類,內部幫助咱們實現了只是基本功能:認證、權限、頻率控制, 但凡是數據庫、分頁等操做都須要手動去完成,比較原始。 class GenericAPIView(APIView) def post(...): pass b.繼承GenericViewSet(ViewSetMixin,generics.GenericAPIView) 首先他的路由就發生變化 若是繼承它以後,路由中的as_view須要填寫對應關係 在內部也幫助咱們提供了一些方便的方法: get_queryset get_object get_serializer get_serializer_class get_serializer_context filter_queryset 注意:要設置queryset字段,不然會拋出斷言的異常。 代碼 只提供增長功能 只繼承GenericViewSet class TestView(GenericViewSet): serialazer_class = xxx def creat(self,*args,**kwargs): pass # 獲取數據並對數據 c. 繼承 modelviewset --> 快速快發 -ModelViewSet(增刪改查全有+數據庫操做) -mixins.CreateModelMixin(只有增),GenericViewSet -mixins.CreateModelMixin,DestroyModelMixin,GenericViewSet 對數據庫和分頁等操做不用咱們在編寫,只須要繼承相關類便可。 示例:只提供增長功能 class TestView(mixins.CreateModelMixin,GenericViewSet): serializer_class = XXXXXXX *** modelviewset --> 快速開發,複雜點的genericview、apiview
- 如何編寫?寫類並實現authenticators 請求進來認證須要編寫一個類,類裏面有一個authenticators方法,咱們能夠自定義這個方法,能夠定製3類返回值。 成功返回元組,返回none爲匿名用戶,拋出異常爲認證失敗。 源碼流程:請求進來先走dispatch方法,而後封裝的request對象會執行user方法,由user觸發authenticators認證流程 - 方法中能夠定義三種返回值: - (user,auth),認證成功 - None , 匿名用戶 - 異常 ,認證失敗 - 流程: - dispatch - 再去request中進行認證處理
# 對匿名用戶,根據用戶IP或代理IP做爲標識進行記錄,爲每一個用戶在redis中建一個列表 { throttle_1.1.1.1:[1526868876.497521,152686885.497521...], throttle_1.1.1.2:[1526868876.497521,152686885.497521...], throttle_1.1.1.3:[1526868876.497521,152686885.497521...], } 每一個用戶再來訪問時,需先去記錄中剔除過時記錄,再根據列表的長度判斷是否能夠繼續訪問。 '如何封IP':在防火牆中進行設置 -------------------------------------------------------------------------- # 對註冊用戶,根據用戶名或郵箱進行判斷。 { throttle_xxxx1:[1526868876.497521,152686885.497521...], throttle_xxxx2:[1526868876.497521,152686885.497521...], throttle_xxxx3:[1526868876.497521,152686885.497521...], } 每一個用戶再來訪問時,需先去記錄中剔除過時記錄,再根據列表的長度判斷是否能夠繼續訪問。 \如1分鐘:40次,列表長度限制在40,超過40則不可訪問
Flask自由、靈活,可擴展性強,透明可控,第三方庫的選擇面廣, 開發時能夠結合最流行最強大的Python庫,
# 依賴jinja2模板引擎 # 依賴werkzurg協議
# blueprint把實現不一樣功能的module分開.也就是把一個大的App分割成各自實現不一樣功能的module. # 在一個blueprint中能夠調用另外一個blueprint的視圖函數, 但要加相應的blueprint名.
# Flask組件 flask-session session放在redis flask-SQLAlchemy 如django裏的ORM操做 flask-migrate 數據庫遷移 flask-script 自定義命令 blinker 信號-觸發信號 # 第三方組件 Wtforms 快速建立前端標籤、文本校驗 dbutile 建立數據庫鏈接池 gevnet-websocket 實現websocket # 自定義Flask組件 自定義auth認證 參考flask-login組件
# a、簡單來講,falsk上下文管理能夠分爲三個階段: 一、'請求進來時':將請求相關的數據放入上下問管理中 二、'在視圖函數中':要去上下文管理中取值 三、'請求響應':要將上下文管理中的數據清除 # b、詳細點來講: 一、'請求剛進來': 將request,session封裝在RequestContext類中 app,g封裝在AppContext類中 並經過LocalStack將requestcontext和appcontext放入Local類中 二、'視圖函數中': 經過localproxy--->偏函數--->localstack--->local取值 三、'請求響應時': 先執行save.session()再各自執行pop(),將local中的數據清除
# g是貫穿於一次請求的全局變量,當請求進來將g和current_app封裝爲一個APPContext類, # 再經過LocalStack將Appcontext放入Local中,取值時經過偏函數在LocalStack、local中取值; # 響應時將local中的g數據刪除:
RequestContext #封裝進來的請求(賦值給ctx) AppContext #封裝app_ctx LocalStack #將local對象中的數據維護成一個棧(先進後出) Local #保存請求上下文對象和app上下文對象
# 由於經過維護成列表,能夠實現一個棧的數據結構,進棧出棧時只取一個數據,巧妙的簡化了問題。 # 還有,在多app應用時,能夠實現數據隔離;列表裏不會加數據,而是會生成一個新的列表 # local是一個字典,字典裏key(stack)是惟一標識,value是一個列表
請求進來時,能夠根據URL的不一樣,交給不一樣的APP處理。藍圖也能夠實現。 #app1 = Flask('app01') #app2 = Flask('app02') #@app1.route('/index') #@app2.route('/index2') 源碼中在DispatcherMiddleware類裏調用app2.__call__, 原理其實就是URL分割,而後將請求分發給指定的app。 以後app也按單app的流程走。就是從app.__call__走。
gevent-websocket
#快速建立前端標籤、文本校驗;如django的ModelForm
# flask中的信號blinker 信號主要是讓開發者但是在flask請求過程當中定製一些行爲。 或者說flask在列表裏面預留了幾個空列表,在裏面存東西。 簡言之,信號容許某個'發送者'通知'接收者'有事情發生了 @ before_request有返回值,blinker沒有返回值 # 10個信號 request_started = _signals.signal('request-started') #請求到來前執行 request_finished = _signals.signal('request-finished') #請求結束後執行 before_render_template = _signals.signal('before-render-template')#模板渲染前執行 template_rendered = _signals.signal('template-rendered')#模板渲染後執行 got_request_exception = _signals.signal('got-request-exception') #請求執行出現異常時執行 request_tearing_down = _signals.signal('request-tearing-down')#請求執行完畢後自動執行(不管成功與否) appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 請求上下文執行完畢後自動執行(不管成功與否) appcontext_pushed = _signals.signal('appcontext-pushed') #請求app上下文push時執行 appcontext_popped = _signals.signal('appcontext-popped') #請求上下文pop時執行 message_flashed = _signals.signal('message-flashed')#調用flask在其中添加數據時,自動觸發