9期面試題總結

 

 

一、django請求生命週期html

page1image1657312 page1image1657520 page1image1657728 page1image1657936

- wsgi, 他就是socket服務端,用於接收用戶請求並將請求進行初次封裝,而後將請求交給web框架 (Flask、Django)前端

- 中間件,幫助咱們對請求進行校驗或在請求對象中添加其餘相關數據,例如:csrf、request.session - 路由匹配 根據瀏覽器發送的不一樣url去匹配不一樣的視圖函數
- 視圖函數,在視圖函數中進行業務邏輯的處理,可能涉及到:orm、templates => 渲染
- 中間件,對響應的數據進行處理。vue

- wsgi,將響應的內容發送給瀏覽器。html5

二、什麼是wsgi中文名:web服務器網關接口 實現該協議的模塊:python

- wsgiref
- werkzurg - uwsgimysql

PythonWeb服務器網關接口(Python Web Server Gateway Interface,縮寫爲WSGI)是Python應用程序或框 架和Web服務器之間的一種接 口,是一種協議,實現該協議的模塊有uwsgi、wsgiref和werkzeug,這些模 塊本質上就是socket服務端,用於接收用戶請求並將請求進行初次封裝,而後將請求交給web框架 (Flask、Django)git

三、FBV和CBV本質是同樣的,沒有優劣之分,可根據不一樣的需求來使用視圖github

- FBV 基於函數的視圖 url - 函數web

- CBV 基於類的視圖 url - view面試

四、restful規範(10) 什麼是接口?

- URL - 約束

# 約束繼承(實現)了他的類中必須含有IFoo中的方法 interface

IFoo:
def func(self): pass

class Foo(IFoo): def func(self):

print(11111)

五、restful 10大規範:首先restful是一種軟件架構風格或者說是一種設計風格,並非標準,它只是提供了一組設計原則

和約束條件,主要用於客戶端和服務器交互類的軟件。
 就像設計模式同樣,並非必定要遵循這些原則,而是基於這個風格設計的軟件能夠更簡潔,更有層
次,咱們能夠根據開發的實際狀況,
 作相應的改變。它裏面提到了一些規範,例如:

一、在url接口中推薦使用Https協議,讓網絡接口更加安全(Https是Http的安全版,即HTTP下加入 SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL(安全套接層協議))

二、url中能夠體現這是個API接口 三、url中還能夠體現版本號,不一樣的版本能夠有不一樣的接口,使其更加簡潔,清晰
四、restful 提倡面向資源編程,因此在url接口中儘可能要使用名詞,不要使用動詞 五、此外url中還能夠添加條件去篩選匹配 六、能夠根據Http不一樣的method,進行不一樣的資源操做(5種方法:GET / POST / PUT / DELETE

/ PATCH) 七、響應式應該包含狀態碼

1) 200 OK - [GET]:服務器成功返回用戶請求的數據,該操做是冪等的(Idempotent)。 2) 201 CREATED -[POST/PUT/PATCH]:用戶新建或修改數據成功。
3) 202 Accepted - [*]:表示一個請求已經進入後臺排隊(異步任務)
4) 204 NO CONTENT - [DELETE]:用戶刪除數據成功。

5) 400 INVALID REQUEST -[POST/PUT/PATCH]:用戶發出的請求有錯誤,服務器沒有進行 新建或修改數據的操做,該操做是冪等的。

6) 401 Unauthorized - [*]:表示用戶沒有權限(令牌、用戶名、密碼錯誤)。
7) 403 Forbidden - [*] 表示用戶獲得受權(與401錯誤相對),可是訪問是被禁止的。
8) 404 NOT FOUND - [*]:用戶發出的請求針對的是不存在的記錄,服務器沒有進行操做,該

操做是冪等的。
9) 406 Not Acceptable - [GET]:用戶請求的格式不可得(好比用戶請求JSON格式,可是隻有

XML格式)。
10) 410Gone -[GET]:用戶請求的資源被永久刪除,且不會再獲得的。
11) 422Unprocesable entity - [POST/PUT/PATCH] 當建立一個對象時,發生一個驗證錯誤。 12) 500INTERNAL SERVER ERROR - [*]:服務器發生錯誤,用戶將沒法判斷髮出的請求是否

成功。
八、應該有返回值,並且格式爲統一的json格式 九、應該返回錯誤信息 十、返回結果中要提供幫助連接,即API最好作到Hypermedia。

六、rest framework框架(10大組件)&& 談談你對 django rest framework框架的認識?- 路由,

- 能夠經過as_view傳參數,根據請求方式不一樣執行相應的方法

- 能夠在url中設置一個結尾,相似於: .json - 視圖,

- 幫助開發者提供了一些類,並在類中提供了多個方法以供咱們使用。 - 版本,

- 在url中設置version參數,用戶請求時候傳入參數。在request.version中獲取版本,根據版本不一樣 作不一樣處理

- 認證,
- 寫一個類並註冊到認證類,在類的的authticate方法中編寫認證邏輯。

- 認證成功(user,auth) - raise AuthticateFaild(....) - None

- 權限
- 寫一個類並註冊到權限類,在類的的has_permission方法中編寫認證邏輯。

- True

- False - 頻率限制

- 寫一個類並註冊到頻率類,在類的的 allow_request/wait 方法中編寫認證邏輯。 allow_request

- True

- False 若是返回False,那麼就要執行wait - 解析器,

- 根據ContentType請求頭,選擇不一樣解析器對 請求體中的數據進行解析。 POST /index/ http1.1.\r\nhost:11.11.11.11\r\nContent-Type:url-formendo....

\r\n\r\nuser=alex&age=123
POST /index/ http1.1.\r\nhost:11.11.11.11\r\nContent-Type:application/json\r\n\r\n{....}

- 分頁
- 對從數據庫中獲取到的數據進行分頁處理: SQL -> limit offset

- 根據頁碼:http://www.luffycity.com/api/v1/student/?page=1&size=10
- 根據索引:http://www.luffycity.com/api/v1/student/?offset=60&limit=10- 根據加密:http://www.luffycity.com/api/v1/student/?page=erd8

問題:爲何頁碼越大速度越慢,以及如何解決? 緣由:頁碼越大向後須要掃描的行數越多,由於每次都是從0開始掃描。 解決:

- 限制顯示的頁數

- 記錄當前頁數據ID最大值和最小值,再次分頁時,根據ID現行篩選,而後再分頁。 - 序列化

- 對queryset序列化以及對請求數據格式校驗。 - 渲染器

- 根據URL中傳入的後綴,決定數據如何渲染到到頁面上。 面試題:你寫的視圖類都繼承過哪些類?

class View(object):
class APIView(View):
class GenericAPIView(views.APIView):
class GenericViewSet(ViewSetMixin, generics.GenericAPIView) class ModelViewSet(mixins.CreateModelMixin,

page3image3670640 page3image3670224 page3image3671264

mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):

七、爲何會出現跨域問題?跨域是指從一個域名的網頁去請求另外一個域名的資源。瀏覽器出於安全的考慮,不容許不一樣源

的請求;
由於瀏覽器收到同源策略的限制,當前域名的js只能讀取同域下的窗口屬性。 同源策略:不一樣的域名, 不一樣端口, 不一樣的協議不容許共享資源,保障瀏覽器安全。

處理方法:
一、jsonp 跨域方法 同源策略會阻止ajax請求;不阻止具備src屬性的標籤,因此動態建立script標籤便可。具體以下:

咱們提供一個 script 標籤。請求頁面中的數據, 同時傳入一個回調函數的名字。服務器端獲得名字後,

拼接函數執行格式的字符串。發送回瀏覽器。script 在下載代碼之後並執行, 執行的就是這個函數調 用形式的字符串,

所以就將本地函數調用了.同時拿到了從服務器端獲得的數據。 二、CORS 跨域

CORS 是在 es5 以後提出的跨域方案. 只須要在服務器配置一個跨域響應頭接口

容許你的域名來獲取個人數據 response['Access-Control-Allow-Origin'] = "*"

容許你攜帶Content-Type請求頭 response['Access-Control-Allow-Headers'] = "Content-Type"

容許你發送DELETE,PUT response['Access-Control-Allow-Methods'] = "DELETE,PUT"

CORS請求頭的注意事項: - 簡單請求

- 複雜請求
- 會發送兩次請求

- 首先會發送options請求作預檢
- 而後再發送真正的 PUT/POST....請求

只要同時知足如下兩大條件,就屬於簡單請求。 (1) 請求方法是如下三種方法之一:

HEAD GET POST

(2)HTTP的頭信息不超出如下幾種字段: Accept

Accept-Language Content-Language

text/plain

Last-Event-ID Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、

非簡單請求的CORS請求,會在正式通訊以前,增長一次HTTP(options)查詢請 求,稱爲"預檢"請求(preflight)。

瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可使 用哪些HTTP動詞和頭信息字段。只有獲得確定答覆,

瀏覽器纔會發出正式的XMLHttpRequest請求,不然就報錯。

與jsonp相比的優勢:
一、 JSONP只能實現GET請求,而CORS支持全部類型的HTTP請求。
二、 使用CORS,開發者可使用普通的XMLHttpRequest發起請求和得到數據,比起JSONP

有更好的錯誤處理。
三、 JSONP主要被老的瀏覽器支持,它們每每不支持CORS,而絕大多數現代瀏覽器都已經

支持了CORS。

八、面試題(1)

var name = '景女神'

function Foo(name,age){ this.name = name;

this.age = age; this.getName = function(){

console.log(this.name); # 文州

(function(){
console.log(this.name); # 女神

})()

obj = new Foo('文州',19) obj.getName()

(2)
var name = '景女神'

function Foo(name,age){ this.name = name;

this.age = age; this.getName = function(){

console.log(this.name); # 文州 var that = this
(function(){

console.log(that.name); # 文州 })()

} }

} }

obj = new Foo('文州',19) obj.getName()

(3)
var name = '景女神' obj = {

name:'文州',
age: 19, getName:function(){

} }

console.log(this.name); # 文州 var that = this
(function(){

console.log(that.name); # 文州 })()

obj.getName()

九、你理解的Http協議?- 創建在tcp之上

- 一次請求一次響應而後斷開鏈接(無狀態、短鏈接) - 請求和響應
發送:請求頭\r\n\r\n請求體

host:www.luffy.com\r\ncontent-type:application/json\r\n\r\n請求體 響應:響應頭\r\n\r\n響應體

Http協議就是一個傳輸數據格式(官名是超文本傳輸協議)。 我以前在學習django框架的時候,是從socket服務端開始學起。 本身創造了一個socket服務器來充當:網站。 瀏覽器當socket客戶端。

更清楚的明白到底http協議是什麼?
- 請求頭 請求體
- 響應頭 響應體 一次請求響應後,斷開鏈接(無狀態,短鏈接)。

page6image3672928

常見的請求頭:
- Content-Type

原則上瀏覽器會根據Content-Type來決定顯示返回的消息體內容的格

式。
- User-Agent
- referer, 來的,能夠作圖片防盜鏈。

告訴HTTP服務器,客戶端使用的操做系統和瀏覽器的名稱和版本 提供了Request的上下文信息的服務器,告訴服務器我是從哪一個連接過

- Host 請求報頭域主要用於指定被請求資源的Internet主機和端口號,它一般 從HTTP URL中提取出來

- cookie

常見的狀態碼: -200
- 302

最重要的header,將cookie的值發送給HTTP服務器

請求成功 OK

重定向,新的URL會在response 中的Location中返回,瀏覽器將會自動使用新 的URL發出新的Request

- 304 - 400 - 403 - 404 - 500 - 503

表明上次的文檔已經被緩存了, 還能夠繼續使用 客戶端請求與語法錯誤,不能被服務器所理解 服務器收到請求,可是拒絕提供服務,好比沒有找到cookie 請求資源不存在(輸錯了URL) 服務器發生了不可預期的錯誤 服務器當前不能處理客戶端的請求,一段時間後可能恢復正常

常見的請求方法:
- GET/POST/DELETE/PUT/PATCH/OPTIONS

常見的請求體: Form表單提交:

POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\nusername=alex&password=123&... Ajax請求:

POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\nusername=alex&password=123&... POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\n{「username」:"alex","password":123}

補充:django中獲取請求體 - request.POST

- request.body

十、中間件定義:中間件是一個用來處理Django的請求和響應的框架級別的鉤子。它是一個輕量、低級別的插 件系統, 用於在全局範圍內改變Django的輸入和輸出。每一箇中間件組件都負責作一些特定的功能。 說的直白一點中間件是幫助咱們在視圖函數執行以前和執行以後均可以作一些額外的操做, 它本質上就是一個自定義類,類中定義了幾個方法,Django框架會在請求的特定的時間去執行這些 方法。

內置的5個方法:
process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs) process_template_response(self,request,response) process_exception(self, request, exception) process_response(self, request, response)

使用中間件作過什麼? - 內置

page7image3672512 page7image3670432 page7image3674176

- csrf

- session - 自定義

- 登陸認證:再也不須要在每一個函數中添加裝飾器
- 權限:當用戶登陸時候獲取當前用戶全部權限並放入session,而後再次訪問其餘頁 面,獲取當前url並在session中 進行匹配。若是沒有匹配成功,則在中間件返回「無權訪問」

- 跨域,
- jsonp,動態建立一個script標籤。
- cors,設置響應頭 應用:本地開始先後端分離的時使用。

11. 如何實現的訪問頻率控制?使用IP/用戶帳號做爲鍵,每次的登錄時間戳做爲值,構造一個字典形式的數據,存起來,每次登 陸時把時間戳列表的元素進行判斷,把超時的刪掉,再計算列表剩餘的元素數就能作到頻率限制了 匿名用戶:使用IP控制,可是沒法徹底控制,由於用戶能夠換代理IP 登陸用戶:使用帳號控制,可是若是有不少帳號,也沒法限制

十二、django組件:contenttype組件的做用:能夠經過兩個字段讓表和N張表建立FK關係

例如:
class Course(models.Model):
"""專題課程"""
name = models.CharField(max_length=128, unique=True) course_img = models.CharField(max_length=255)

# 不會在數據庫生成列,只用於幫助你進行查詢 policy_list = GenericRelation("PricePolicy")

class PricePolicy(models.Model):
"""價格與有課程效期表"""
content_type = models.ForeignKey(ContentType) # 關聯course or degree_course object_id = models.PositiveIntegerField()

#不會在數據庫生成列,只用於幫助你進行添加和查詢 content_object = GenericForeignKey('content_type', 'object_id')

1三、原生Ajax:XMLHttpRequest對象:var xhr = new XMLHttpRequest() xhr.onreadystatechange = function(){

if(xhr.readyState == 4){
// 已經接收到所有響應數據,執行如下操做 var data = xhr.responseText;

console.log(data); }

};
xhr.open('POST', "/test/", true);

// 設置請求頭
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');

// 發送請求 xhr.send('n1=1;n2=2;');

1四、ORM相關

- only only()裏的字段,表示只取相關字段的內容,注意:當only後進行for循環取值 時,若是取那些不在only括號內字段,會致使再次進行數據庫查詢,效率會差不少

和only相反,括號內的字段表示不取相關字段的內容
用於主動進行連表查詢 FK時用,至關於主動作join(一次連表查詢,連表查詢

屢次單表操做,避免連表查詢損耗;先查詢想要的數據,而後構造條件,如:

- defer
- seleted_related
速度會相對慢點)
- prefetch_related id=[1,2,3],再次查詢其餘表根據id作條件。

- F - Q

用來更新獲取原來值的功能,例如:Uinfo.objects.all().update(age=F("age")+1) 用於構造複雜的查詢條件的,使用方法有對象方法和直接建立建立對象方法

Q功能詳解: 數據庫的查詢條件咱們可使用filter,在filter裏面的能夠是兩個條件他們之間是and的關

系,也能夠是一個字典,例以下面的代碼 models.Uinfo.objects.all().filter(id=1,name='李偉') conditon={

'id':'1',

'name':'李偉' }

models.Uinfo.objects.all().filter(**conditon)

除了上面的方法,咱們還能夠加Q的對象,例如:
from django.db.models import Q models.Uinfo.objects.all().filter(Q(id=1))#條件是id爲1的時候 models.Uinfo.objects.all().filter(Q(id=1)|Q(id__gt=3))#條件是或的關係 models.Uinfo.objects.all().filter(Q(id=1) & Q(id=4))# 條件是and的關係

Q的另一種用法
#q1 裏面的條件都是or的關係

q1=Q()
q1.connector = 'OR' q1.children.append(('id',1)) q1.children.append(('id',3)) q1.children.append(('id',6))

#q2裏面的條件都是or的關係

q2=Q()
q2.connector = 'OR' q2.children.append(('c',2)) q2.children.append(('c',4)) q2.children.append(('c',6))

#con 經過and的條件把q1和q2 聯繫到一塊 con=Q()

con.add(q1,'AND') con.add(q2,'AND')

Q能把查詢相互嵌套

- 經過ORM寫偏原生SQL: - extra

Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params= (1,))
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])

Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by= ['-nid'])

- raw
# 執行原生SQL models.UserInfo.objects.raw('select * from userinfo')

# 若是SQL是其餘表時,必須將名字設置爲當前UserInfo對象的主鍵列名 models.UserInfo.objects.raw('select id as nid from 其餘表')

# 爲原生SQL設置參數
models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])

name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

page10image1789056

- 原生SQL

from django.db import connection, connections
cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) row = cursor.fetchone() # fetchall()/fetchmany(..)
PS: 選擇數據庫
queryset = models.Course.objects.using('default').all()

a. 需求: 只取某n列 queryset=[ {},{}]

models.User.objects.all().values( 'id','name')

queryset=[ (),()] models.User.objects.all().values_list( 'id','name')

queryset=[ obj,obj]
result = models.User.objects.all().only('id','name','age')
# result = models.User.objects.all().defer('id','name','age') for item in reuslt:
print(item.id,item.name,item.age)

b. 需求: 打印全部用戶姓名以及部門名稱

class depart: title = ....

class User:
name = ...
dp = FK(depart)
c.
select * from user
result = models.User.objects.all() for item in result: print(item.name)

select * from user left join depart on user.dp_id = depart.id result = models.User.objects.all().selected_related('dp')
for item in result:
print(item.name,item.dp.title )

注意:數據量比較大,不會使用FK,容許出現數據冗餘,爲了提升查詢訪問效率。

1五、支付寶支付相關1.正式申請:須要營業執照 2.測試:沙箱測試環境 3.公鑰私鑰:支付寶的公鑰和商家的私鑰 4.加密方式:rsa

5.支付成功後,斷電宕機無影響,支付寶會在24小時內發送信息讓用戶確認,只有用戶確認後纔算 是真正的成功
成功:return HttpResponse('success')
6.精度:小數點後兩位

1六、git rebase的做用?保持提交記錄的整潔。

1七、使用git時,若是代碼出現bug,大家是如何解決?建立一個bug分支,而後進行bug處理,處理完畢後,合併到master分支。 刪除bug分支
回到dev分支繼續開發。

1八、redis是什麼?用於操做內存的軟件。

數據存儲模式有2種:cache-only,persistence; 一、cache-only即只作爲「緩存」服務,不持久數據,數據在服務終止後將消失,此模式下也將 不存在「數據恢復」的手段,是一種安全性低/效率高/容易擴展的方式; 二、persistence即爲內存中的數據持久備份到磁盤文件,在服務重啓後能夠恢復,此模式下數據 相對安全。

對於persistence持久化存儲,Redis提供了兩種持久化方法: Redis DataBase(簡稱RDB)

RDB是在某個時間點將數據寫入一個臨時文件,持久化結束後,用這個臨時文件 替換上次持久化的文件,達到數據恢復。 優勢:使用單獨子進程來進行持久化,主進程不會進行任何IO操做,保證了redis 的高性能 缺點:RDB是間隔一段時間進行持久化,若是持久化之間redis發生故障,會發生 數據丟失。因此這種方式更適合數據要求不嚴謹的時候

Append-only file (簡稱AOF)
Append-only file,將「操做 + 數據」以格式化指令的方式追加到操做日誌文件的尾 部,在append操做返回後(已經寫入到文件或者即將寫入),才進行實際的數據變 更,「日誌文件」保存了歷史全部的操做過程;當server須要數據恢復時,能夠直 接replay此日誌文件,便可還原全部的操做過程。AOF相對可靠,它和mysql中 bin.log、apache.log、zookeeper中txn-log簡直殊途同歸。AOF文件內容是字符串,非 常容易閱讀和解析。 優勢:能夠保持更高的數據完整性,若是設置追加file的時間是1s,若是redis發生 故障,最多會丟失1s的數據;且若是日誌寫入不完整支持redis-check-aof來進行日誌 修復;AOF文件沒被rewrite以前(文件過大時會對命令進行合併重寫),能夠刪除 其中的某些命令(好比誤操做的flushall)。 缺點:AOF文件比RDB文件大,且恢復速度慢。

- 至關因而大字典 - 單進程單線程
- 5大數據類型

字符串 列表 集合 字典

有序集合

redis的列表操做
- 左右操做,雙向連接

- 阻塞
- 經過yield建立一個生成器完成一點一點獲取(經過字典操做的源碼來的靈感)

def list_iter(key,count=100): index = 0

while True:
data_list = conn.lrange('k1', index, index+count-1) if not data_list:

return index += count

for item in data_list: yield item

PS: 隊列:先進先出 棧:後進先出

- 事務+一次發送多個命令:
conn = redis.Redis(host='47.94.172.250',port=6379,password='Luffy!4321')

pipe = conn.pipeline(transaction=True) pipe.multi()

pipe.set('k2','123') pipe.hset('k3','n1',666) pipe.lpush('k4','laonanhai')

pipe.execute()

1九、redis中使用鏈接池本質,維護一個已經和服務端鏈接成功的socket。 之後再次發送數據時,直接獲取一個socket,直接send數據。

20、解決數據庫頁數越大速度越慢。- 限制頁數

- 記錄當前頁最大ID、最小ID 錯誤答案:

- 掃描索引表
- 再去數據庫表中獲取數據

2一、作代碼review如何作代碼review?

- 建立review分支:

誰來作代碼review? - 組長

- 帶你的人

2二、問題: 怎麼在github上給別人修改代碼?一、fork

github上 不是有個fork麼, 好,那麼給別人的項目提交代碼的方式就有了,先fork下別人的代 碼,因而你的github上就出現了同名的項目,這個項目就屬於你本身了,你把這個本身的項目 git clone到本地,修修改改,而後push到你本身的項目裏;

二、pull request
在github上你的項目頁面有個按鈕,叫Pull request,對 你點它就會把你的修改發到對方的項目 裏,人還會收到郵件呢,由原項目主人決定是否接受你的修改

2三、github不用反覆輸入用戶名密碼登陸Https:

https://用戶名:密碼@github.com/WuPeiqi/dbhot.git
git remote add origin https://用戶名:密碼@github.com/WuPeiqi/dbhot.git

SSH:
git@github.com:WuPeiqi/dbhot.git

步驟:
一、大多數 Git 服務器都會選擇使用 SSH 公鑰來進行受權。系統中的每一個用戶都必須提 供一個公鑰用於受權,沒有的話就要生成一個。生成公鑰的過程在全部操做系統上都差 很少。 首先先確認一下是否已經有一個公鑰了。SSH 公鑰默認儲存在帳戶的主目錄下的 ~/.ssh 目錄。進去看看。
命令:cd ~/.ssh
二、關鍵是看有沒有用 something 和 something.pub 來命名的一對文件,這個 something 通 常就是 id_dsa 或 id_rsa。有 .pub 後綴的文件就是公鑰,另外一個文件則是密鑰。假如沒有 這些文件,或者乾脆連 .ssh 目錄都沒有,能夠用 ssh-keygen 來建立。該程序在 Linux/Mac 系統上由 SSH 包提供,而在 Windows 上則包含在 MSysGit 包裏。 命令:ssh-keygen 三、它先要求你確認保存公鑰的位置(.ssh/id_rsa),而後它會讓你重複一個密碼兩次, 若是不想在使用公鑰的時候輸入密碼,能夠留空。 如今,全部作過這一步的用戶都得把它們的公鑰給你或者 Git 服務器的管理員(假設 SSH 服務被設定爲使用公鑰機制)。他們只須要複製 .pub 文件的內容而後發郵件給管理 員。
命令:cat ~/.ssh/id_rsa.pub
四、在GitHub上的我的中心的settings裏的 SSH and GPG keys 中添加已生成的 SSH keys 即 可。

2四、 在django中應用redis:

1. 自定義使用redis import redis

2. 使用第三方組件
pip3 install django-redis

page14image3675840 page14image3678752 page14image3678960

配置:
CACHES = {

"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} # "PASSWORD": "密碼",
}

} }

使用:
conn = get_redis_connection("default")

2五、關於微信消息推送網址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login基於:已認證的微信服務號 主動推送微信消息。
前提:關注服務號
環境:沙箱環境

總結:

  1. 註冊帳號

    appID:wx89085e915d351cae appsecret:64f87abfc664f1d4f11d0ac98b24c42d

    網頁受權獲取用戶基本信息:47.98.134.86 或 域名

  2. 關注公衆號(已認證的服務號)

  3. 生成二維碼,用戶掃描; 將用戶信息發送給微信,微信再將數據發送給設置redirect_uri地址(md5值)

  4. 回調地址:47.98.134.86/callback/ - 受權

    - 用戶md5
    - 獲取wx_id

    在數據庫中更新設置:wx_id

  5. 發送消息(模板消息)

    - wx_id
    - access_token(2小時有效期)

2六、互聯網協議OSI四層、五層和七層模型

   四層:應用層、傳輸層、網絡層和網絡接口層
   五層:應用層、傳輸層、網絡層、數據鏈路層和物理層
page15image5768624
七層:應用層、表示層、會話層、傳輸層、網絡層、數據鏈路層和物理層
  每層運行常見物理設備:
     傳輸層:四層交換機、四層路由器
     網絡層:路由器和三層交換機
     數據鏈路層:網橋、以太網交換機、網卡
     物理層:中繼器、集線器和雙絞線

每層運行常見的協議: 傳輸層:TCP和UDP協議 網絡層:IP協議 數據鏈路層:arp協議

2七、理解socketSocket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。在設計模式中,Socket其 實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面, 對用戶來講,一組簡單的接口就是所有,讓Socket去組織數據,以符合指定的協議。 其實socket就是一個模塊。咱們經過調用模塊中已經實現的方法創建兩個進程之間的鏈接和通訊。 也有人將socket說成ip+port,由於ip是用來標識互聯網中的一臺主機的位置,而port是用來標識這臺 機器上的一個應用程序。 因此咱們只要確立了ip和port就能找到一個應用程序,而且使用socket模塊來與之通訊。

2八、理解TCP協議和UDP協議TCP---傳輸控制協議,提供的是面向鏈接、可靠的字節流服務。當客戶和服務器彼此交換數據前,必 須先在雙方之間創建一個TCP鏈接,以後才能傳輸數據。TCP提供超時重發,丟棄重複數據,檢驗 數據,流量控制等功能,保證數據能從一端傳到另外一端。 UDP---用戶數據報協議,是一個簡單的面向數據報的運輸層協議。UDP不提供可靠性,它只是把應 用程序傳給IP層的數據報發送出去,可是並不能保證它們能到達目的地。因爲UDP在傳輸數據報前 不用在客戶和服務器之間創建一個鏈接,且沒有超時重發等機制,故而傳輸速度很快。

2九、理解TCP協議中的三次握手和四次揮手創建鏈接的三次握手

TCP是因特網中的傳輸層協議,使用三次握手協議創建鏈接。當主動方發出SYN鏈接請求後, 等待對方回答SYN+ACK[1],並最終對對方的 SYN 執行 ACK確認。這種創建鏈接的方法能夠 防止產生錯誤的鏈接。[1]
TCP三次握手的過程以下:

客戶端發送SYN(SEQ=x)報文給服務器端,進入SYN_SEND狀態。 服務器端收到SYN報文,迴應一個SYN (SEQ=y)ACK(ACK=x+1)報文,進入 SYN_RECV狀態。 客戶端收到服務器端的SYN報文,迴應一個ACK(ACK=y+1)報文,進入Established狀 態。 三次握手完成,TCP客戶端和服務器端成功地創建鏈接,能夠開始傳輸數據了。

page17image1800704

首先Client端發送鏈接請求報文,Server段接受鏈接後回覆ACK報文,併爲此次鏈接分配 資源。Client端接收到ACK報文後也向Server段發生ACK報文,並分配資源,這樣TCP連 接就創建了。

斷開鏈接的四次揮手: 假設Client端發起中斷鏈接請求,也就是發送FIN報文。Server端接到FIN報文後,意思是說"我 Client端沒有數據要發給你了",可是若是你還有數據沒有發送完成,則沒必要急着關閉Socket, 能夠繼續發送數據。因此你先發送ACK,"告訴Client端,你的請求我收到了,可是我還沒準備 好,請繼續你等個人消息"。這個時候Client端就進入FIN_WAIT狀態,繼續等待Server端的FIN 報文。當Server端肯定數據已發送完成,則向Client端發送FIN報文,"告訴Client端,好了,我 這邊數據發完了,準備好關閉鏈接了"。Client端收到FIN報文後,"就知道能夠關閉鏈接了,但 是他仍是不相信網絡,怕Server端不知道要關閉,因此發送ACK後進入TIME_WAIT狀態,如 果Server端沒有收到ACK則能夠重傳。「,Server端收到ACK後,"就知道能夠斷開鏈接了"。 Client端等待了2MSL後依然沒有收到回覆,則證實Server端已正常關閉,那好,我Client端也可 以關閉鏈接了。Ok,TCP鏈接就這樣關閉了!

page18image1801376

30、TCP協議中爲何鏈接的時候是三次握手,關閉的時候倒是四次握手?由於當Server端收到Client端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文 是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不 會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。 只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步 握手。

3一、TCP協議中在斷開鏈接時,爲何TIME_WAIT狀態須要通過2MSL(最大報文段生存時 間)才能返回到CLOSE

狀態?雖然按道理,四個報文都發送完畢,咱們能夠直接進入CLOSE狀態了,可是咱們必須假象網絡是不 可靠的,有能夠最後一個ACK丟失。因此TIME_WAIT狀態就是用來重發可能丟失的ACK報文。

3二、接口的冪等性?(是否會形成2次傷害)一個接口經過1次相同的訪問,再對該接口進行N次相同的訪問時候,對資源不造影響,那麼就認爲 接口具備冪等性。

好比:
GET, 第一次獲取結果、第二次也是獲取結果對資源都不會形成影響,冪等。 POST,第一次新增數據,第二次也會再次新增,非冪等。
PUT, 第一次更新數據,第二次不會再次更新,冪等。 PATCH,第一次更新數據,第二次不會再次更新,非冪等。 DELTE,第一次刪除數據,第二次不在再刪除,冪等。

3三、Https和Http區別? 一、首先Https是Http的安全版,即HTTP下加入SSL層就是Https;

二、默認端口號不一樣,Http是80端口,Https是443端口; 三、Http是超文本傳輸協議,信息是明文傳輸,能夠自定義證書,在服務端建立一對證書,在客戶 端必須攜帶證書;

Https是須要到ca申請證書(購買),在服務端建立一對證書,在客戶端去機構獲 取證書,數據加密後發給

   我們的服務單,而證書機構須要把公鑰給改機構。

3四、路飛學城相關
1)購物車購買數量有限制嗎? -- 有,防止有人惡意破壞,把大量商品加入購物車,不購買,佔 用redis的負擔
2)購物車是否設置超時時間? -- 能夠設置,也能夠不設置,其實只設置一下購物車購買數量即 可。 (.conn.expire("shopping_car_1_1", 60*30))
3)爲何把購物車信息放入redis?

1.購物車的操做只是個臨時狀態,不須要放入數據庫;

2.須要頻繁對購物車進行修改,放入redis的話操做速度快。 4)爲何要開發這個項目?

1.提升在線 教育的 完課率 (學成率) 2.項目的具體內容有:

        課程分兩種,學位課和專題課
        購買課程時,能夠選擇不一樣的價格策略來進行學習
        闖關式學習,對於學位課來講,咱們不會一次性把所有課程的視頻給學員,會進行闖關
        式學習,
             只有噹噹前階段經過導師測試後,學員纔有資格進行下一步的學習
       導師篩選,咱們對導師會有很嚴格的篩選,只有經過咱們的嚴格考覈,纔有資格作咱們
       的導師
       導師監督,人都有惰性心理,因此咱們會對咱們導師有嚴格的要求,導師必須對學員負
       責,天天都要有跟進記錄,

無論是電話仍是QQ、微信,都要有記錄上傳系統,這些都會和他們的獎懲關 聯

        導師答疑時間,不一樣的課程,不一樣的價位,會有不一樣的答疑時間限制,在規定時間內,
        導師必須給學員進行回覆
        報名時學員有權利選擇導師,在學習期間,學員也有權利提出更換導師
        獎懲措施,對於導師來講,每個導師帶領一個學員時,咱們都會給導師帳戶存入必定
        的獎金,直到學員畢業後才能提現,在學員學習期間,若是導師有不負責現象,咱們會
        作出相應的懲罰措施,作必定扣除獎金機制;對於學員來講,學員可以按時或者提早在
        規定時間內學習完一個模塊,做業和測試成績優異的話,咱們會給必定的獎勵。

5)這個項目的開發週期和團隊構成 週期:初期開發到上線時間是大約四個月,以後一直在作網站的維護,bug的處理,開展一些 活動,廣告之類的,

        還有一些小功能的開發
     團隊構成:

開發
導師後臺:stark組件和rbac 大約須要1人 管理後臺:stark組件和rbac 大約須要1人

主站: vue.js

api接口 運維(1人)

測試(1人) 產品經理(1人) UI設計(1人) 運營(1人) 銷售(5人) 全職導師(2人) 簽約導師(。。。)

6)購買課程流程 加入購物車 去結算中心

去支付 7)路飛的主站業務

課程
課程列表

課程詳細

     課程大綱、導師、推薦課程

價格策略

加入購物車

課程章節和課時

常見問題

評論

深科技 文章列表

     文章詳細
     收藏
     點贊
     評論
     推薦其餘優秀文章

支付
購物車

     結算中心
     當即支付
     知識點:

大約須要1人 2.5我的,組長偶爾會負責一些,不算是整我的力

redis
支付寶支付
微信消息推送 構建數據結構 優惠券+貝里+支付寶支付

我的中心

課程中心 8)播放視頻:cc視頻

加密 非加密

3五、Django、Flask和Tornado區別?Django:簡單的說Django是一個大而全的Web框架,內置了不少組件,ORM、admin、Form、 ModelForm、中間件、信號和緩存等。

基於wsgi協議部署的,使用wsgiref模塊實現此協議; Flask:微型的小而精的Web框架,可擴展性強,內置的組件不多,須要引入第三方組件實現功能業 務,若是開發簡單的項目,

使用Flask比較快速和方便。若是開發大型項目,須要引入大量的第三方組件,這時Flask會越 來越像Django框架。基於wsgi協議部署,使用werkzeug模塊實現此協議,模板系統由 Jinja2提 供。

Tornado:是一個輕量級的Web框架,可擴展性強,用於快速開發簡單程序,用於強大的異步非阻塞 和內置WebSocket功能。

3六、Flask 10大基礎知識一、配置文件

Flask的配置文件全都放在 app.config 裏,怎樣修改配置文件呢? 首先在項目裏建立一個 settings.py 文件,在文件裏能夠自定義修改配置文件,好比: class Config(object):

DEBUG = False
TESTING = False
DATABASE_URL = 'sqlite://:memory:'

class ProductionConfig(Config):
DATABASE_URL = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config): DEBUG = True

class TestingConfig(Config): TESTING = True

而後在 app.py 文件裏引入自定義修改的配置文件 app.config.from_object("settings.DevelopmentConfig")
# 能夠根據不一樣的測試環境,引入不一樣的配置文件
PS:內部的實現原理知識點 -- 獲得一個字符串的路徑 "settings.Foo" ,怎樣找到類並獲取其中 的大寫的靜態字段。

在 settings.py 文件裏設置自定義的 Foo 類 靜態屬性必須是大寫的,
class Foo:

DEBUG = True TEST = True

page21image3683120

在 app.py 文件中引入

import importlib 持傳遞字符串來導入模塊

path = "settings.Foo"

p,c = path.rsplit('.',maxsplit=1) m = importlib.import_module(p) cls = getattr(m,c)

# 若是找到這個類? for key in dir(cls):

if key.isupper(): print(key,getattr(cls,key))

二、路由系統 一般有3種定義路由函數的方法: 1.使用flask.Flask.route() 修飾器。 2.使用flask.Flask.add_url_rule()函數。

def index():
return 'index'

app.add_url_rule('/index', None, index)

三、視圖

# 提供Pythonimport語法和(__import__()函數)的實現,提供支

# 至關於實現了 # 至關於實現了

import settings settings.Foo

-- 第一個參數是 url 路由,第二個參數是 endpoint

,第三個參數是 函數名 3.直接訪問基於werkzeug路由系統的flask.Flask.url_map。 最經常使用的@app.route()裝飾器

可以加參數:
參數一,url @app.route("/index") -- url 沒有參數時

@app.route("/index/<int:nid>") -- url 有參數時,"<>" 這個是格式,int 是 定義參數類型

參數二,methods 默認的是 GET 請求 @app.route("/index/<int:nid>", methods= ['GET','POST'])
參數三,endpoint 定義 url 別名,用於反向生成 url ,不寫時默認的是被裝飾的函數名

@app.route("/index/<int:nid>", methods=['GET','POST'],endpoint='index') 反向解析時,須要引入 url_for ,使用: url_for('endpoint') 或者 url_for('index',nid=555)

參數: rule,

view_func, endpoint=None, methods=None, strict_slashes=None, redirect_to=None,

defaults=None, {'k':'v'}爲函數提供參數

URL規則
視圖函數名稱 名稱,用於反向生成URL,即: url_for('名稱')

容許的請求方式,如:["GET","POST"] 對URL最後的 / 符號是否嚴格要求,

重定向到指定地址 默認值,當URL中無參數,函數須要參數時,使用defaults=

subdomain=None,

子域名訪問

CBV
import functools

from flask import Flask,views app = Flask(__name__)

def wrapper(func): @functools.wraps(func) def inner(*args,**kwargs):

return func(*args,**kwargs) return inner

class UserView(views.MethodView): methods = ['GET']

decorators = [wrapper,]

def get(self,*args,**kwargs): return 'GET'

def post(self,*args,**kwargs): return 'POST'

app.add_url_rule('/user',None,UserView.as_view('uuuu'))

if __name__ == '__main__': app.run()

自定義路由匹配正則:
from flask import Flask,url_for

app = Flask(__name__)

# 步驟一:定製類
from werkzeug.routing import BaseConverter class RegexConverter(BaseConverter):

""" 自定義URL匹配正則表達式 """

def __init__(self, map, regex): super(RegexConverter, self).__init__(map) self.regex = regex

def to_python(self, value): """

路由匹配時,匹配成功後傳遞給視圖函數中參數的值

:param value: :return:
"""
return int(value)

def to_url(self, value): """

使用url_for反向生成URL時,傳遞的參數通過該方法處理,返回的值用於 生成URL中的參數

:param value: :return:

"""
val = super(RegexConverter, self).to_url(value) return val

# 步驟二:添加到轉換器 app.url_map.converters['reg'] = RegexConverter

"""
1. 用戶發送請求
2. flask內部進行正則匹配
3. 調用to_python(正則匹配的結果)方法
4. to_python方法的返回值會交給視圖函數的參數

"""

# 步驟三:使用自定義正則 @app.route('/index/<reg("\d+"):nid>') def index(nid):

print(nid,type(nid))

print(url_for('index',nid=987)) return "index"

if __name__ == '__main__': app.run()

四、請求相關 請求相關信息

request.method request.args request.form request.values request.cookies request.headers request.path request.full_path

request.script_root request.url request.base_url request.url_root request.host_url request.host request.files

obj = request.files['the_file_name'] obj.save('/var/www/uploads/' + secure_filename(f.filename))

五、響應 響應體:

1.return "asdfgh" -- 直接返回字符串
2.return jsonify({'k1':'v1'}) -- 返回序列化後的字符串
3.return render_template('index.html') -- 返回一個頁面
4.return redirect('www.baidu.com') -- 重定向
定製響應頭:
obj = make_response('kkk')
obj.headers['hhhhh'] = '555'
obj.set_cookie('key', 'value')
return obj -- 返回Response對象,make_response()函數能夠接受1個,2個或3個參數

   問題:怎樣實現登錄驗證功能
   方法一:

@app.route('/index') def index():

if not session.get('user'):
return redirect(url_for('login'))

return render_template('index.html')
session.get('user') 判斷,這個方法顯得很麻煩,不用

方法二:
import functools

def auth(func): @functools.wraps(func)

def inner(*args,**kwargs):
if not session.get('user'):

return redirect(url_for('login')) ret = func(*args,**kwargs)
return ret

return inner

@app.route('/index') @auth
def index():

return render_template('index.html',stu_dic=STUDENT_DICT)

# 在每一個須要驗證的函數裏都加上

     把驗證邏輯放在裝飾器裏,對每個須要驗證的函數進行裝飾
     應用場景:比較少的函數中須要額外添加功能。

版本三:before_request @app.before_request

def auth():
if request.path == '/login':

return None

if session.get('user'): return None

return redirect('/login')

六、模板渲染
基本數據類型:能夠執行python語法,如:dict.get() list[0],也可使用django模板語言的語 法,如:dict.name
傳入函數

django 能夠後面不加括號,函數自動執行

flask 不會自動執行,和python的語法同樣,須要在函數名的後面加上括號才能執行 全局定義函數

@app.template_global() def sb(a1, a2):

# {{sb(1,9)}} return a1 + a2

@app.template_filter() def db(a1, a2, a3):

# {{ 1|db(2,3) }} return a1 + a2 + a3

模板繼承:和 django 的模板繼承同樣

安全過濾器 前端:{{u|safe}}

後端:MarkUp('asdfg')


{% macro info(name, type='text', value='') %}

<h1>宏</h1>
<input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="submit" value="提交">

{% endmacro %} {{ info('n1') }} {{ info('n2') }}

一個宏能夠被不一樣的模板使用,咱們能夠聲明在一個單獨的模板文件中,導入的方法是 {% from 'form.html' import info %}
而後就能夠在這個html文件中直接使用這個宏函數了

七、session
flask:當請求剛到來時,flask讀取 cookie 中 session 對應的值,將該值解密並反序列化成字 典,放入內存以便視圖函數使用。
視圖函數:

@app.route('/ses') def ses():

session['k1'] = 123 session['k2'] = 456 del session['k1']

return "Session"

session['xxx'] = 123 session['xxx']

當請求結束時,flask 會讀取內存中字典的值,進行序列化+加密,寫入到用戶cookie中。

八、flash -- 閃現,在 session 中存儲一個數據,讀取時經過 pop 將數據移除。 from flask import Flask,flash,get_flashed_messages
@app.route('/page1')
def page1():

flash('臨時數據存儲','error') flash('sdfsdf234234','error') flash('adasdfasdf','info')

return "Session"

@app.route('/page2') def page2():

print(get_flashed_messages(category_filter=['error'])) return "Session"

九、中間件 __call__方法何時觸發?

用戶發起請求時,才執行 任務:在執行call方法以前,作一個操做,call方法執行以後作一個操做。 class Middleware(object):

def __init__(self,old): self.old = old

def __call__(self, *args, **kwargs):

ret = self.old(*args, **kwargs) return ret

if __name__ == '__main__':
app.wsgi_app = Middleware(app.wsgi_app) app.run()

十、特殊的裝飾器 1.before_request

2.after_request 示例:

from flask import Flask app = Flask(__name__)

@app.before_request def x1():

print('before:x1') return '滾'

@app.before_request def xx1():

print('before:xx1')

@app.after_request def x2(response):

print('after:x2') return response

@app.after_request def xx2(response):

print('after:xx2') return response

@app.route('/index') def index():

print('index') return "Index"

@app.route('/order') def order():

print('order') return "order"

if __name__ == '__main__': app.run()

3. before_first_request

from flask import Flask app = Flask(__name__)

@app.before_first_request def x1():

print('123123')

@app.route('/index') def index():

print('index') return "Index"

@app.route('/order') def order():

print('order') return "order"

if __name__ == '__main__': app.run()

4. template_global 5. template_filter 6. errorhandler

@app.errorhandler(404) def not_found(arg):

print(arg)
return "沒找到"

3七、Flask之藍圖 目標:給開發者提供目錄結構 其餘:

自定義模板、靜態文件等 某一類 url 添加前綴

-- 在註冊藍圖的時候能夠給 url 添加前綴 app.register_blueprint(us, url_prefix='/api')

給一類 url 添加裝飾器(例如: before_request)

3八、threading.local 做用:爲每一個線程建立一個獨立的空間,使得線程對本身的空間中的數據進行操做(數據隔離)。 應用:DBUtils 中爲每一個線程建立一個數據庫鏈接,注意:Flask中並無使用 threading.local ,而是 使用了 LocalStack ,細化到了協程。
import threading
from threading import local
import time

obj = local()

def task(i): obj.num = i

obj.sleep(2) print(obj.num, i)

for i in range(10):
t = threading.Thread(target = task, args = (i,)) t.start()

問題:如何獲取一個線程的惟一標記?threading.get_ident() 根據字典自定義一個相似於 threading.local功能?

import time import threading

DIC = {}

def task(i):
ident = threading.get_ident() if ident in DIC :

DIC[ident]['num'] = i else:

DIC[ident] = {'num': i } time.sleep(2)

print(DIC[ident]['num'], i) for i in range(10):

t = threading.Thread(target = task, arg = (i,)) t.start()

根據字典自定義一個爲每一個協程開闢空間進行存取數據 import time

import threading import greenlet

DIC = {} def task(i):

# ident = threading.get_ident() ident = greenlet.getcurrent()
if ident in DIC: DIC[ident]['xxxxx'] = i

else:
DIC[ident] = {'xxxxx':i } time.sleep(2)

print(DIC[ident]['xxxxx'],i)

for i in range(10):
t = threading.Thread(target=task,args=(i,))

t.start()

經過 getattr / setattr 構造出來 threading.local 的增強版(協程) imort time

import treading import greenlet try:

get_ident = greenlet.getcurrent except Exception as e:

get_ident = threading.get_ident class Local(object):

DIC = {}
def __getattr__(self, item):

ident = get_ident() if ident in self.DIC:

self.DIC[ident][key] = value else:

self.DIC[ident] = {key:value}

obj = Local()

def task(i): obj.xxxxx = i

time.sleep(2) print(obj.xxxxx,i)

for i in range(10):
t = threading.Thread(target=task,args=(i,) t.start()

3九、Flask的上下文管理
請求到來的時候:
# ctx = RequestContext(self, environ) # self是app對象,environ請求相關的原始數據

# ctx.request = Request(environ) # ctx.session = None

# 將包含了request/session的ctx對象放到「空調」 {

1232:{ctx:ctx對象} 1231:{ctx:ctx對象} 1211:{ctx:ctx對象} 1111:{ctx:ctx對象} 1261:{ctx:ctx對象}

}

視圖函數:
from flask import reuqest,session

request.method

  請求結束:
      根據當前線程的惟一標記,將「空調」上的數據移除。

40、Flask之偏函數 偏函數是從Python2.5引入的一個概念,經過functools模塊被用戶調用。偏函數是將所要承載的函數做爲 partial()函數的第一個參數,原函數的各個參數依次做爲partial()函數後續的參數,除非使用關鍵字參數。 偏函數能夠幫助開發者自動傳遞參數。
例如:

from functools import partial def func(x, y, z):

return x + y + z new_func = partial(func, 10)

print(func(10, 10, 10)) # 30

print(new_func(10, 10)) # 30
應用場景:在Flask的源碼裏遇過:
請求進來觸發 def __call__() 方法 -- > def wsgi_app() --> ctx.push() --> def push() -- > _request_ctx_stack.push(self) --> globals.py文件裏 有關於偏函數的使用

request = LocalProxy(partial(_lookup_req_object, 'request')) session = LocalProxy(partial(_lookup_req_object, 'session')) g = LocalProxy(partial(_lookup_app_object, 'g'))

PS:
其實能夠看到無論request仍是session最後都是經過getattr(top, name)獲取的,也就是說確定有一個上下

文對象同時保持request和session。咱們只要一處導入request,在任何視圖函數中均可以使用request,關鍵 是每次的都是不一樣的request對象,說明獲取request對象確定是一個動態的操做,否則確定都是相同的 request。這裏的魔法就是_lookup_req_object函數和LocalProxy組合完成的。 LocalProxy是werkzeug.local.py中 定義的一個代理對象,它的做用就是將全部的請求都發給內部的_local對象。

當咱們調用request.method時會調用_lookup_req_object,對request的任何調用都是對 _lookup_req_object返回對象的調用。既然每次request都不一樣,要麼調用top = _request_ctx_stack.top返回的 top不一樣,要麼top.request屬性不一樣,在flask中每次返回的top是不同的,因此request的各個屬性都是變化 的。

如今須要看看_request_ctx_stack = LocalStack(),LocalStack其實就是簡單的模擬了堆棧的基本操做, push,top,pop,內部保存的線程本地變量是在多線程中request不混亂的關鍵。
4一、面向對象中的 super 方法的用途

1、根據 mro 的順序執行方法

2、主動執行Base類的方法 4二、基於列表實現棧

class Stack(object): def __init__(self):

self.data = []

def push(self,val): self.data.append(val)

def pop(self):
return self.data.pop()

def top(self):
return self.data[-1]

_stack = Stack()

_stack.push('哈哈') _stack.push('呵呵')

print(_stack.pop())

print(_stack.pop()) 4三、在類中什麼是函數,什麼是方法?

class Foo(object):

def func(self): pass

# 執行方式一 obj = Foo() obj.func() # 方法

# 執行方式二

Foo.func(123) # 函數 4四、面向對象中雙下劃線方法

__str__ __init__ __repr__ __new__

__getattr__ __setattr__ __delattr__

單例模型用到

rest framework 序列化的時候用到了

在 flask Local對象用到
__call__ 在 Flask 的源碼請求入口和 Django 的請求入口(WSGIHandler.__call__)都用到了

setitem
getitem delitem,
class Foo(object):

def __getitem__(self, item): return 1

def __setitem__(self, key, value): pass

def __delitem__(self, key): pass

obj = Foo() obj['k1'] obj['k1'] = 123 del obj['k1']

dict,api封裝返回數據時:BaseResponse mro, 顯示繼承順序 slots,Local對象,顯示類中能調用的方法

4五、請求上下文管理(ctx):request,session
- 請求到來以後wsgi會觸發__call__方法,由__call__方法再次調用wsgi_app方法 - 在wsgi_app方法中:
- 首先將 請求相關+空session 封裝到一個RequestContext對象中,即:ctx。
- 將ctx交給LocalStack對象,再由LocalStack將ctx添加到Local中,Local結構: __storage__ = {

1231:{stack:[ctx,] } }

- 根據請求中的cookie中提取名稱爲sessionid對應的值,對cookie進行加密+反序列化,再次賦值給ctx 中的session

-> 視圖函數

- 把session中的數據再次寫入到cookie中。 - 將ctx刪除

- 結果返回給用戶瀏覽器 - 斷開socket鏈接

4六、關於Flask中的g
g對象是application context,能夠存儲任何你想存儲的內容,如數據庫鏈接或登陸的用戶。應用

上下文flask._app_ctx_stack 和 flask.g 差很少, 能夠保存一些特定的數據到這兩個對象內部, 固然這些數 據只在"一個請求"的生命週期中有效. 不過flask._app_ctx_stack 推薦給extension的開發者使用, flask.g

留給web 開發使用. 若是要"跨請求"來共享數據, 須要使用 session 對象.可使用get()方法來獲取g的屬 性,如:
user=getattr(flask.g,'user',None)
user=flask.g.get('user',None)

g 的生命週期:
g 是面向單個 request 的,一個 request 處理完,g 裏的東西就沒啦。(注意,這裏說的 request

不是指 request context,從 0.10 版本開始,g 已是面向 app context 了。這裏寫面向單個 request 是爲了幫助提問者理解問題中提到的區別,僅考慮在 web 下的場景。)
g 和 session 的比較:

session 是能夠跨 request 使用的,session 的數據是通過加密後存儲在 cookie 裏的,用戶每次 request 都會把這些 cookie 信息發回來,從而實現跨 request 使用。
g是面向單個 request 的,一個 request 處理完,g 裏的東西就沒啦。(注意,這裏說的 request

不是指 request context,從 0.10 版本開始,g 已是面向 app context 了。這裏寫面向單個 request是爲 了幫助提問者理解問題中提到的區別,僅考慮在 web 下的場景。)
g 和全局變量的比較:

全局變量在項目啓動後就會引進,並且全局變量不會改變,不會消失;g 是在有請求的時候才

被設置,一次請求結束後會自動消失。 4七、什麼是響應式佈局?

簡而言之,就是一個網站可以兼容多個終端--而不是爲每一個終端作一個特定的版本。這個概念是爲 解決移動互聯網瀏覽而誕生的。 響應式佈局能夠爲不一樣終端的用戶提供更加溫馨的界面和更好的用戶體驗,並且隨着目前大屏幕移 動設備的普及,用"大勢所趨"來形容也不爲過。隨着愈來愈多的設計師採用這個技術,咱們不只看 到不少的創新,還看到了一些成形的模式。

優勢:
面對不一樣分辨率設備靈活性強
可以快捷解決多設備顯示適應問題
缺點:
兼容各類設備工做量大,效率低下 代碼累贅,會出現隱藏無用的元素,加載時間加長 其實這是一種折中性質的設計解決方案,多方面因素影響而達不到最佳效果 必定程度上改變了網站原有的佈局結構,會出現用戶混淆的狀況 原理:使用了媒介查詢:@media屬性

4八、MySQL 數據庫的引擎 1.Innodb引擎

支持事務 支持鎖

行鎖和表鎖:可是當SQL語句沒有指定要鎖定的具體行範圍的話,Innodb 也會鎖全表。 支持外鍵約束

2.MyIASM引擎 MyIASM是MySQL默認的引擎,不支持事務,也不支持行級鎖和外鍵,只支持表級鎖。

兩種引擎的比較: 大尺寸的數據集趨向於選擇InnoDB引擎,由於它支持事務處理和故障恢復。數據庫的大小決 定了故障恢復的時間長短,InnoDB能夠利用事務日誌進行數據恢復,這會比較快。主鍵查詢 在InnoDB引擎下也會至關快,不過須要注意的是若是主鍵太長也會致使性能問題。大批的 INSERT語句(在每一個INSERT語句中寫入多行,批量插入)在MyISAM下會快一些,可是 UPDATE語句在InnoDB下則會更快一些,尤爲是在併發量大的時候。

4九、Flask 上下文管理

LocalProxy:它是werkzeug.local.py中定義的一個代理對象,它的做用就是將全部的請求都發給內部 的_local對象。
主要包含兩種:

請求上下文(ctx = RequestContext())裏面含有兩種信息 request \ session app 上下文(app_ctx = AppContext())裏面含有兩種信息 app \ g 詳細流程:
一、程序啓動後:

啓動項目的全局變量,實例化了兩個對象,並建立了兩個Stack 兩個Local:

local1 = { }
local2 = { }

兩個LocalStack: _request_ctx_stack _app_ctx_stack

二、請求到來後 對數據進行封裝:

ctx = RequestContext(request,session)

app_ctx = AppContext(app,g) 保存數據:

將包含了(app,g)數據的app_ctx對象,利用 _app_ctx_stack(貝貝,LocalStack())將 app_ctx添加到Local中

storage = { 1231:{stack:[app_ctx(app,g),]}

} 將包含了request,session數據的ctx對象,利用_request_ctx_stack(劉淞,

LocalStack()),將ctx添加到Local中 storage = {

1231:{stack:[ctx(request,session),]} }

問題: Local是什麼?做用?

答:存儲數據,在Flask中給每個協程開闢一個內存空間,保證數據之間的隔離 LocalStack是什麼?做用?

答:將Local的數據,字典storage對應的值維護成一個棧(棧裏面有 push 和 pop 這兩 個方法),而後把數據存儲到Local 中

三、視圖函數處理:
from flask import Flask,request,session,current_app,g

索引

id name pwd email
數據表中有上面4個字段,若是把 name pwd email 設成聯合索引,只有下面的狀況能命中

select * from tb where name='x'
select * from tb where name='x' and pwd='123'
select * from tb where name='x' and email='123@qq.com' select * from tb where name='x' and pwd='123' and email='xs' 當下面兩種狀況的時候不會命中索引
select * from tb where pwd='123'

app = Flask(__name__)

@app.route('/index') def index():

# 去請求上下文中獲取值 _request_ctx_stack request.method # 找小東北獲取值 session['xxx'] # 找龍泰獲取值

# 去app上下文中獲取值:_app_ctx_stack print(current_app)
print(g)

return "Index"

if __name__ == '__main__': app.run()

app.wsgi_app

經過LocalProxy對象+偏函數,調用LocalStack去Local中獲取響應ctx、app_ctx中封裝的 值。
問題:
爲何要把 ctx=requestssion app_ctx = app/g ? 答:由於離線腳本須要使用app_ctx。

四、請求結束 _app_ctx_stack.pop()

_request_ctx_stack.pop() 50、MySQL 數據庫的索引

索引做用:加速查找+約束。 索引種類:

- 主鍵索引:加速查找、不重複、非空 - 惟一索引:加速查找、不重複
- 普通索引:加速查找
- 聯合索引:加速查找

- 聯合惟一索引:加速查找、不重複 PS:聯合索引遵循最左前綴原則。

page37image5782144

select * from tb where pwd='123' and email='123@qq.com'

page37image5783600

名詞:
- 覆蓋索引:在索引文件中就能夠把想要的數據獲得。

MySQL能夠利用索引返回select列表中的字段,而沒必要根據索引再次讀取數據 文件,包函全部知足查詢須要的數據的索引稱爲覆蓋索引。 注意:若是使用覆蓋索引,必定要注意select列表中只取出須要的列,不可 select * ,由於若是將全部字段一塊兒作索引會致使索引文件過大,查詢性能下 降。

select name from tb1;
- 索引合併:使用多個單列索引去查找數據。

一、索引合併是把幾個索引的範圍掃描合併成一個索引。

二、索引合併的時候,會對索引進行並集,交集或者先交集再並集操做,以便合併 成一個索引。

三、這些須要合併的索引只能是一個表的。不能對多表進行索引合併。

建立索引,但沒法命中索引: https://www.cnblogs.com/wupeiqi/articles/5716963.html

5一、MySQL 數據庫受權
MySQL 賦予用戶權限命令的簡單格式可歸納爲: grant 權限 on 數據庫對象 to 用戶 詳解:https://www.cnblogs.com/bethal/p/5512755.html

5二、MySQL 數據庫視圖 (View)是一種虛擬存在的表。其內容與真實的表類似,包含一系列帶有名稱的列和行數據。

可是視圖並不在數據庫中以存儲的數據的形式存在。行和列的數據來自定義視圖時查詢所引用的基 本表,而且在具體引用視圖時動態生成。
視圖是存儲在數據庫中的查詢的SQL 語句,它主要出於兩種緣由:安全緣由, 視圖能夠隱藏一些 數據,如:社會保險基金錶,能夠用視圖只顯示姓名,地址,而不顯示社會保險號和工資數等,另 一緣由是可以使複雜的查詢易於理解和使用。

:

CREATE VIEW 視圖名(列1,列2...) AS SELECT (列1,列2...) FROM ...;5三、MySQL 數據庫觸發器

MySQL包含對觸發器的支持。觸發器是一種與表操做有關的數據庫對象,當觸發器所在表上出現指 定事件時,將調用該對象,即表的操做事件觸發表上的觸發器的執行。 在對某張表進行:增、刪、改的先後自定義操做。
在MySQL中,建立觸發器語法以下:

CREATE TRIGGER trigger_name trigger_time
trigger_event ON tbl_name
FOR EACH ROW

trigger_stmt

page38image3693520 page38image3695392 page38image3695808 page38image3697056

weiv etaerc圖視建創

圖視

和查看數據庫(show databases;)查看錶格(show tables;)同樣,查看觸發器的語法如

下:

SHOW TRIGGERS[FROM schema_name];和刪除數據庫、刪除表格同樣,刪除觸發器的語法以下:

DROPTRIGGER[IF EXISTS][schema_name.]trigger_name觸發器的執行順序

咱們創建的數據庫通常都是 InnoDB 數據庫,其上創建的表是事務性表,也就是事務安全的。這 時,若SQL語句或觸發器執行失敗,MySQL 會回滾事務,有:

1若是 BEFORE 觸發器執行失敗,SQL 沒法正確執行。 2SQL 執行失敗時,AFTER 型觸發器不會觸發。

3AFTER 類型的觸發器執行失敗,SQL 會回滾。

5四、MySQL 數據庫之函數 對數據中的值進行操做

MySQL數據庫提供了不少函數包括:

   數學函數;
   字符串函數;
   日期和時間函數;
   條件判斷函數;
   系統信息函數;
   加密函數;
   格式化函數;

具體參考:https://www.cnblogs.com/kissdodog/p/4168721.html5五、MySQL 數據庫之存儲過程

存儲過程簡介
SQL語句須要先編譯而後執行,而存儲過程(Stored Procedure)是一組爲了完成特定功能的 SQL語句集,經編譯後存儲在數據庫中,用戶經過指定存儲過程的名字並給定參數(若是該 存儲過程帶有參數)來調用執行它。

存儲過程是可編程的函數,在數據庫中建立並保存,能夠由SQL語句和控制結構組成。當想 要在不一樣的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是很是有用 的。數據庫中的存儲過程能夠看作是對編程中面向對象方法的模擬,它容許控制數據的訪問 方式。

存儲過程的優勢:

(1).加強SQL語言的功能和靈活性:存儲過程能夠用控制語句編寫,有很強的靈活性,能夠完 成複雜的判斷和較複雜的運算。

(2).標準組件式編程:存儲過程被建立後,能夠在程序中被屢次調用,而沒必要從新編寫該存儲 過程的SQL語句。並且數據庫專業人員能夠隨時對存儲過程進行修改,對應用程序源代碼毫 無影響。

page39image3695184 page39image3698928 page39image3698512 page39image3699136 page39image3699344 page39image3699552 page39image3699760 page39image3699968

,器發觸除刪

,器發觸看查

(3).較快的執行速度:若是某一操做包含大量的Transaction-SQL代碼或分別被屢次執行,那麼 存儲過程要比批處理的執行速度快不少。由於存儲過程是預編譯的。在首次運行一個存儲過 程時查詢,優化器對其進行分析優化,而且給出最終被存儲在系統表中的執行計劃。而批處 理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。

(4).減小網絡流量:針對同一個數據庫對象的操做(如查詢、修改),若是這一操做所涉及的 Transaction-SQL語句被組織進存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳 送的只是該調用語句,從而大大減小網絡流量並下降了網絡負載。

(5).做爲一種安全機制來充分利用:經過對執行某一存儲過程的權限進行限制,可以實現對相 應的數據的訪問權限的限制,避免了非受權用戶對數據的訪問,保證了數據的安全。

     對結果集合返回值進行復雜操做。

DELIMITER //
CREATE PROCEDURE myproc(OUT s int) BEGIN
SELECT COUNT(*) INTO s FROM students; END
//
DELIMITER ;

具體可參考:https://www.cnblogs.com/mark-chan/p/5384139.html 5六、Flask 中的組件有哪些?

page40image3703296 page40image3703504 page40image3703712

一、flask-session 二、DBUtils 三、wtforms 四、sqlalchemy 五、flask-script 六、flask-migrate

數據庫鏈接池

a. 增長 runserver

b. 位置傳參

c.關鍵字傳參

5七、使用裝飾器,如何不改變函數簽名
給裝飾器的內層函數加上裝飾器 functools.wraps(func) ,會保留原函數的元信息,書寫形式例如:def wrapper(func):

@functools.wraps(func) def inner(*args,**kwargs):

return func(*args,**kwargs) return inner

5八、類的私有化 通常狀況下,類的私有化對象是不能調用的,若是想調用,就要寫成這種形式的 class Foo(object):

def __init__(self, name, age): self.name = name self.__age = age

體程過 ]... 性特[ )]]...型類據數 名數參 ]TUONI|TUO|NI[,[型類據數 名數參 ]TUONI|TUO|NI[[(名程過 ERUDECORP ETAERC

法語建創的程過儲存LQSyM

def func(self): print(self.__age)

obj = Foo('oldboy', 50) print(obj.name) print(obj._Foo__age) obj.func()

# 必定能使用

# 對象調用類的私有屬性的方法

注意:私有化,在子類父類之間是不能互相調用的
相關文章
相關標籤/搜索