django框架,內置組件多,自身功能強大,是一個大而全的框架,ORM、Admin、中間件、Form、ModelFrom、信號、緩存、csrf等
flask框架,內置組件少,但第三方豐富,可擴展性強,是一個微小型框架,組件有flask-session、flask-SQLAlchemy、wtforms、flask-migrate、flask-script、blinker
相同點:
兩個框架都是基於wsgi協議實現的,只是默認使用的wsgi模塊不同。 django:wsgiref模塊 flask:werkzurg模塊
不一樣點:他們各自處理請求的方式不一樣:
django: 經過將請求封裝成Request對象,在依次經過中間件,在視圖中經過參數進行傳遞。
flask:經過上下文管理實現。
Tornado框架:
Tornado是一個輕量級的Web框架,主要功能:異步非阻塞+內置WebSocket
a. wsgi, 建立socket服務端,用於接收用戶請求並對請求進行初次封裝。
b. 中間件,對全部請求在到來以前,響應以前定製一些操做。
c. 路由匹配,在url和視圖函數對應關係中,根據當前請求url找到相應的函數。
d. 執行視圖函數,業務處理【經過ORM去數據庫中獲取數據,再去拿到模板,而後將數據和模板進行渲染】
e. 再通過全部中間件
f. 經過wsgi將響應返回給用戶。javascript
一、進行域名解析獲取ip, 先去本地域名服務器,若是沒有再去根域名服務器
二、鏈接成功
三、瀏覽器發送數據
四、服務器接受到數據後處理並響應給瀏覽器
-服務器在次過程當中處理流程較多,-django,flask等
WSGI是web服務網關接口--->應用程序(web框架)與web服務器之間的一種接口css
實現了wsgi協議的模塊本質:編寫了socket服務端,用來監聽用戶請求,若是有請求到來,則將請求進行一次封裝,而後交給 web框架來進行下一步處理。html
模塊有:-wsgiref -werkzurg -uwsgi前端
uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。Nginx中HttpUwsgiModule的做用是與uWSGI服務器進行交換vue
代碼上線時,使用uWSGI:java
一、nginx 作爲代理服務器:負責靜態資源發送(js、css、圖片等)、動態請求轉發以及結果的回覆;python
二、uWSGI 作爲後端服務器:負責接收 nginx 請求轉發並處理後發給 Django 應用以及接收 Django 應用返回信息轉發給 nginx;mysql
三、Django 應用收到請求後處理數據並渲染相應的返回頁面給 uWSGI 服務器。jquery
做用:對全部的請求進行批量處理,能夠在視圖函數執行先後進行自定義操做linux
應用:
-用戶登陸驗證 --->若是使用裝飾器,就必須給每一個函數都添加,太繁瑣
-權限處理 --->用戶登陸成功,將該用戶全部的權限寫入session中,每次訪問時判斷該用戶是否有權限訪問當前的url,這樣就能夠將判斷用戶是否用權限的操做放入中間中
-內置應用
-session
-csrf --->跨站請求僞造,防止用戶直接向服務端發送POST請求。中間件攔截檢驗是否攜帶crsf_token
-全局緩存 --->若是設置了緩存,則請求進來,經過中間件後,則直接去緩存中取數據,而後響應,若是此時的緩存中沒有數據,則走路由匹配、視圖函數,可是在響應時會先將數據放入到緩存當中
-跨域
-cors --->瀏覽器的同源策略(不一樣的域名或不一樣的端口)先後端分離時,本地開發測試使用
一、瀏覽器向服務端發送GET請求,獲取csrf_token: form表單中隱藏的input標籤+保存到cookie中(經過算法)
二、再次發送POST請求時,須要攜帶以前發給瀏覽器的csrf_token,用次crsf_token與cookie中的crsf_token作驗證
三、進行驗證:在process_view中驗證(由於只有在process_view中,才能獲得視圖函數,判斷函數是否須要驗證(加裝飾器能夠避免驗證))
porcess_request
porcess_view
porcess_template_response 只有在視圖函數的返回值中有render方法時才調用此方法
porcess_excepion 處理異常
porcess_response
方法一: $.ajax({ url:'/index', type:'POST', #攜帶csrf_token data:{csrfmiddlewaretoken:'{{ csrf_token }}',name:'alex'} }) 方法二: 前提:引入jquery + 引入jquery.cookie $.ajax({ url: 'xx', type:'POST', data:{name:'oldboyedu'}, #添加請求頭 headers:{ X-CSRFToken: $.cookie('csrftoken') }, dataType:'json', // arg = JSON.parse('{"k1":123}') success:function(arg){ } }) 方法三:使用ajaxSetup, <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>
data headers ajaxSetup()
一、路由分發include:二級路由
二、路由系統中name的做用:反向解析
url(r'^home', views.home, name='home')
在模板中使用 {% url 'home' %}
在視圖中使用 reverse(「home」)
MVC: model view(模塊) controller (視圖)
MTV: model tempalte view
一、CBV和FBV區別:
本質上是沒有什麼區別的,由於它們都是經過對函數進行操做的,而CBV是經過.as_views()方法返回view函數,view函數再調用dispatch(), 在dispstch方法中在經過反射執行get、post、put、patch、delete方法的
二、處理csrf認證及CBV添加裝飾器
普通裝飾器能夠加在get、post等方法上
csrf裝飾器放在dispatch()上或直接加在類上
局部避免csrf的方式: from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator 針對FBV: @csrf_exempt def foo(request): return HttpResponse("foo") 針對CBV: # 方式1 @method_decorator(csrf_exempt,name="dispatch") class IndexView(View): # 方式2 @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): print("hello world") # 執行父類的dispatch方法 res=super(IndexView,self).dispatch(request, *args, **kwargs) print("hello boy") return res @method_decoretor(裝飾器函數) 添加裝飾器 def post(self,request,*args,**kwargs): return HttpResponse('OK')
當請求進來時,將請求相關的數據封裝到environ中,django項目啓動時,執行__call__,將environ賦值給request對象
wsgi: from wsgiref.simple_server import make_server def run_server(environ, start_response): """ environ: 封裝了請求相關的數據 start_response:用於設置響應頭相關數據 """ start_response('200 OK', [('Content-Type', 'text/html')]) return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ] if __name__ == '__main__': httpd = make_server('', 8000, run_server) httpd.serve_forever() Django源碼: class WSGIHandler(base.BaseHandler): request_class = WSGIRequest def __init__(self, *args, **kwargs): super(WSGIHandler, self).__init__(*args, **kwargs) self.load_middleware() def __call__(self, environ, start_response): # 請求剛進來以後 # set_script_prefix(get_script_name(environ)) signals.request_started.send(sender=self.__class__, environ=environ) request = self.request_class(environ) response = self.get_response(request) response._handler_class = self.__class__ status = '%d %s' % (response.status_code, response.reason_phrase) response_headers = [(str(k), str(v)) for k, v in response.items()] for c in response.cookies.values(): response_headers.append((str('Set-Cookie'), str(c.output(header='')))) start_response(force_str(status), response_headers) if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'): response = environ['wsgi.file_wrapper'](response.file_to_stream) return response
- CBV時添加csrf裝飾器,是添加在dispatch上
- 多數據庫配置 allow_relation方法 進行連表
一、增、刪、改、查
增: models.UserInfo.objects.create() obj = models.UserInfo(name='xx') obj.save() models.UserInfo.objects.bulk_create([models.UserInfo(name='xx'),models.UserInfo(name='xx')]) 刪: models.UserInfo.objects.all().delete() 改: models.UserInfo.objects.all().update(age=18) #在原來的基礎上添加1000 models.UserInfo.objects.all().update(salary=F('salary')+1000) 查: filter()· 找不到返回[] exclude() 排除 values() 字典 values_list() 元祖 order_by() order_by('-id') anotate() 用於實現聚合group by查詢 aggregate() 聚合函數 exsit() 是否有結果 reverse() 反轉 distinct() 去重 返回具體的對象 first() laste() get() 找不到報錯
二、value餘value_list
value 返回一個字典
value_list 返回一元祖 (flat=Ture 此時返回一個列表)
三、F、Q
(1)F 用於比較,數字自增
# 查詢評論數大於收藏數的書籍 from django.db.models import F Book.objects.filter(commnetNum__lt=F('keepNum')) #將每一本書的價格提升30元 Book.objects.all().update(price=F("price")+30)
(2)Q 主要是構造複雜的查詢條件。查詢條件爲or(|),and($)
查詢做者名是小仙女或小魔女的 models.Book.objects.filter(Q(authors__name="小仙女")|Q(authors__name="小魔女"))
四、性能優化
(1)select related
一、select_related主要針一對一和多對一關係進行優化。
二、select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。
class Usertype(models.Model): title = models.CharField(max_length=32) class UserInfo(models.Model): name = models.CharField(max_length=32) email = models.CharField(max_length=32) ut = models.ForeignKey(to='UserType') # 1次SQL # select * from userinfo objs = UserInfo.obejcts.all() for item in objs: print(item.name) # n+1次SQL # select * from userinfo objs = UserInfo.obejcts.all() for item in objs: # select * from usertype where id = item.id print(item.name,item.ut.title) # 1次SQL # select * from userinfo inner join usertype on userinfo.ut_id = usertype.id objs = UserInfo.obejcts.all().select_related('ut') for item in objs: print(item.name,item.ut.title)
(2)prftatch related
一、對於多對多字段(ManyToManyField)和一對多字段,可使用prefetch_related()來進行優化
二、prefetch_related()的解決方法是,分別查詢每一個表,而後用Python處理他們之間的關係。(若是鏈表過多,也會影響效率)
(3)only 僅取一條記錄中指定的數據(queryset[obj,obj,obj]) models.UserInfo.objects.only('username','id')
(4)defer 排除一條記錄指定的數據 (queryset[obj,obj]) models.UserInfo.objects.defer('username','id')
五、執行原生SQL
(1)extra 構造查詢條件,如子查詢
Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
(2)raw 執行sql語句
models.UserInfo.objects.raw('select * from userinfo')
(3)execute
1.執行自定義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()
五、using 指定數據庫
使用信號
db first :先建立數據庫,再更新表模型
code first:先寫表模型,再更新數據庫
一、settings中設置鏈接數據庫
二、python manage.py inspectdb > app/models.py
一、模板繼承:{% extends 'layouts.html' %}
二、自定義方法
三、xss攻擊:|safe mark_safe
做用: -用戶請求數據格式驗證
-生產HTML標籤
區別:-From須要本身寫字段
-ModelFrom經過Meta定義
場景:凡是須要進行表單數據驗證的 如:登陸驗證
重寫__init__和使用ModelChoiceField字段類型
from django.forms import Form from django.forms import fields 方法一:從新__init__ class UserForm(Form): name = fields.CharField(label='用戶名',max_length=32) email = fields.EmailField(label='郵箱') ut_id = fields.ChoiceField( # choices=[(1,'二筆用戶'),(2,'悶騷')] 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') def user(request): if request.method == "GET": form = UserForm() return render(request,'user.html',{'form':form}) 方法二:使用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())
表關係是OneToOne,ForeignKey時,有on_delete參數,主要爲了不兩個表裏的數據不一致問題(關聯表中的對象被刪除後,此時表中的對象狀況)
Django2.0裏model外鍵和一對一的on_delete參數 在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():此值設置,會調用外面的值,能夠是一個函數。
將經常使用且不太頻繁修改的數據放入緩存。
之後用戶再來訪問,先去緩存查看是否存在,若是有就返回
不然,去數據庫中獲取並返回給用戶(再加入到緩存,以便下次訪問)
Django中提供了6種緩存方式:
--開發調試(不加緩存)
--內存
--文件
--數據庫
--Memcache緩存(python-memcached模塊)
--Memcache緩存(pylibmc模塊)
安裝第三方組件支持redis:
django-redis組件 設置settings文件
設置緩存:
-全站緩存(中間件)
-視圖函數緩存
-局部模板緩存
信號:django框架內部爲開發者預留下的一些自定製的鉤子,只要在某個信號中註冊了函數,則django內部執行時會自動觸發註冊在信號中的函數
Model signals pre_init # django的modal執行其構造方法前,自動觸發 post_init # django的modal執行其構造方法後,自動觸發 pre_save # django的modal對象保存前,自動觸發 post_save # django的modal對象保存後,自動觸發 pre_delete # django的modal對象刪除前,自動觸發 post_delete # django的modal對象刪除後,自動觸發 m2m_changed # django的modal中使用m2m字段操做第三張表(add,remove,clear)先後,自動觸發 class_prepared # 程序啓動時,檢測已註冊的app中modal類,對於每個類,自動觸發 Management signals pre_migrate # 執行migrate命令前,自動觸發 post_migrate # 執行migrate命令後,自動觸發 Request/response signals request_started # 請求到來前,自動觸發 request_finished # 請求結束後,自動觸發 got_request_exception # 請求異常後,自動觸發 Test signals setting_changed # 使用test測試修改配置文件時,自動觸發 template_rendered # 使用test測試渲染模板時,自動觸發 Database Wrappers connection_created # 建立數據庫鏈接時,自動觸發
應用場景:數據庫中表中的數據發生變化時,日誌記錄
內置:
from django.core import serializers #queryset = [obj,obj,obj] ret = models.BookType.objects.all() data = serializers.serialize("json", ret)
json:
- json.dumps(ensure_ascii=False) #中文亂碼
- json.dumps( cls=JSONEncoder) #自定義JSONEncoder,序列化特殊數據類型
對錶數據進行增刪改查 知識點:單例模式
- 爲公司定製更適用於本身的組件: stark組件
contenttype是django中的一個app,它能夠將django下全部app下的表記錄下來
一張表能夠動態的和N張表進行FK
應用:課程和專題課與間隔策略進行關聯
1、查看訪問的速度、數據庫的行爲、cache命中等信息。
2、尤爲在Mysql訪問等的分析上大有用處(sql查詢速度)
單元測試(Unittest)文本測試(Doctest)
- restful就是一套編寫接口的協議,協議規定了如何規範編寫接口以及設置返回值、狀態碼等信息。 - 最顯著的特色: restful: 給定一個url,根據method不一樣在後端作不一樣的處理,好比:post 建立數據、get獲取數據、put和patch修改數據、delete刪除數據。 使用django中的URL: 就必須給調用者不少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/(主域名下,api功能簡單時)
- 協議 https - 域名 - www.oldboy.com/api 主域名 - api.oldboy.com 子域名 - 版本: - url:www.oldboy.com/api/v1 - 請求頭中也能夠加 - URL資源,名詞 - www.oldboy.com/api/v1/student - 請求方式: - GET/POST/PUT/DELETE/PATCH/OPTIONS/HEADERS/TRACE - 返回值: - www.oldboy.com/api/v1/student/ -> 結果集 - www.oldboy.com/api/v1/student/1/ -> 單個對象 - URL添加條件 - www.oldboy.com/api/v1/student?page=11&size=9 - 狀態碼: - 200 - 300 - 301 - 302 - 400 - 403 - 404 - 500 - 錯誤信息 { code:1000, meg:'xxxx' } - hyperlink { id:1 name: ‘xiangl’, type: http://www.xxx.com/api/v1/type/1/ }
- -由於以前公司要寫一個先後端分離的項目
- 因此就經過查看有關restful相關的技術類文檔和視頻,如: 阮一峯的博客學
---rest—framework框架內部幫助咱們提供了不少組件,咱們只須要經過配置就能夠完成相應操做,如: - 序列化,能夠作用戶請求數據校驗+queryset對象的序列化稱爲json - 解析器,獲取用戶請求數據request.data,會自動根據content-type請求頭的不能對數據進行解析 - 分頁,將從數據庫獲取到的數據在頁面進行分頁顯示。 還有其餘: - 認證 - 權限 - 訪問頻率控制
---也可使用django的CBV來實現,只是須要編寫大量的代碼,下降開發效率。
一、編寫:寫類並實現authticate()
- 方法中能夠定義三種返回值:
-(user,auth),認證成功
- None , 匿名用戶
- 異常 ,認證失敗
二、流程:
- 請求進來走dispatch方法,在dispatch方法中,執行initial()中執行perform_authentication(request)方法,
- 在認證中執行request.user
- 請求進來走dispatch方法,在dispatch方法中,執行initial()中執行check_throttles(request)方法,
def check_throttles(self, request): """ Check if request should be throttled. Raises an appropriate exception if the request is throttled. """ #遍歷throttle對象列表 for throttle in self.get_throttles(): #根據allow_request()的返回值進行下一步操做,返回True的話不執行下面代碼,標識不限流,返回False的話執行下面代碼,還能夠拋出異常 if not throttle.allow_request(request, self): #返回False的話執行 self.throttled(request, throttle.wait())
- 匿名用戶,根據用戶IP或代理IP做爲標識進行記錄,爲每個用戶在redis中建立一個列表
每一個用戶再來訪問時,須要先去記錄中剔除以及過時時間,再根據列表的長度判斷是否能夠繼續訪問。 匿名用戶IP在防火牆中進行設置
- 註冊用戶,根據用戶名或郵箱進行判斷
每一個用戶再來訪問時,須要先去記錄列表中剔除過時時間,再根據列表的長度判斷是否能夠繼續訪問。
1分鐘:40-60次
rest-frmawork視圖中能夠直接繼承10種類,外加View(object),能夠大體分爲三大部分
一、 繼承 APIView(View) 次類屬於rest framework中原始類,內部只是幫助咱們實現了基本功能:認證、權限、頻率控制,但凡涉及到數據庫、分頁等操做都須要手動去完成 二、 繼承 GenericViewSet(ViewSetMixin, generics.GenericAPIView)
class GenericAPIView(APIView)
def post(...):
pass
繼承此類,路由中的as_view()須要填寫對應關係 .as_view({'get':'list','post':'create'}),通常使用此類進行編寫,可擴展性強 在內部也幫助咱們提供了一些方便的方法: - get_queryset - get_object - get_serializer 注意:要設置queryset字段,不然會跑出斷言的異常。 三、 繼承 ModelViewSet()
對數據庫和分頁等操做不用咱們在編寫,只須要繼承相關類便可。此類封裝了大量的組件,操做起來簡單,可是擴展性較差 示例:若是隻提供增長功能,只繼承一下類便可
- mixins.CreateModelMixin,GenericViewSet class TestView(mixins.CreateModelMixin,GenericViewSet): serializer_class = XXXXXXX
對一個接口經過1次訪問以後,再對該接口進行N次相同的訪問時,對資源不造影響,那麼就認爲接口具備冪等性。(主要是第二次訪問時是否會形成傷害)
好比:
GET, 第一次獲取結果、第二次也是獲取結果對資源都不會形成影響,冪等。
POST,第一次新增數據,第二次也會再次新增,非冪等。
PUT, 第一次更新數據,第二次不會再次更新,冪等。
PATCH,第一次更新數據,第二次不會再次更新,非冪等。
DELTE,第一次刪除數據,第二次不在再刪除,冪等。
條件成立,程序繼續執行,不然拋異常
應用場景:rest_framework中繼承類時,一、定義queryset 二、渲染器使用JSON
0、基於wsgi協議下werkzurg模塊
一、路由 @app.route("/login",method=["GET","POST"])
二、視圖 使用FBV
三、session 將簽名的session保存到cookie中
四、特殊裝飾器(相似於中間件) @before_request @after_request
五、message(閃現) 基於Session(先將數據寫入session,在session.pop("xx"))實現的用於保存數據的集合,其特色是:使用一次就刪除。
六、模板 使用jinja2
七、Blueprint(藍圖) 一、項目問價目錄的劃分 二、能夠統一劃分一類url 三、基於before_request(裝飾器)現實一類url的功能
flask:
-flask-session 默認放入cookie,能夠放入redis
-flask-migrate 數據化遷移
-flask-script 自定義命令
-blinker 信號
公共: DBUtils 數據庫鏈接池
wtforms 表單驗證+生成HTML標籤
sqlalchemy 相似於django的orm
自定義:Auth 參考falsk-login
爲每個線程開闢一條內存空間,用來存儲數據
做用:爲每個線程開闢一塊空間進行數據存儲 from threading import local from threading import Thread import time # 示例化local對象 ret=local() def task(s): global ret ret.value=s time.sleep(2) print(ret.value) # 開啓10個線程 for i in range(10): t=Thread(target=task,args=(i,)) t.start()
簡單來講,falsk上下文管理能夠分爲三個階段: 1、請求進來時,將請求相關的數據放入上下文管理中 2、視圖函數中,去上下文管理中取值,並操做 3、請求響應,保存session,要將上下文管理中的數據清除 詳細點來講: 1、請求剛進來,將request,session封裝在RequestContext類中,將app,g封裝在AppContext類中,並經過LocalStack將requestcontext和appcontext放入Local類中 2、視圖函數中,經過localproxy類中調用偏函數--->localstack--->local取值 3、請求響應應時,先執行save.session()再各自執行pop(),將local中的數據清除
threading local和封裝
一、當請求進來時,會將requset和session封裝爲一個RequestContext對象,經過LocalStack將RequestContext放入到Local對象中,
二、由於請求第一次來session是空值,因此執行open_session,給session(uuid4())賦值,再經過視圖函數處理,
三、請求響應時執行save.session,將簽名session寫入cookie中,再去Local中的將數值pop掉。
將local對象中的數據維護成一個棧【ctx,ctx】(先進後出) { 「協程或線程的惟一標識」: { stack:[ctx,ctx,ctx,] } } 爲何維護成一個棧? 一、當是web應用時:無論是單線程仍是多線程,棧中只有一個數據 - 服務端單線程: { 111:{stack: [ctx, ]} } - 服務端多線程: { 111:{stack: [ctx, ]} 112:{stack: [ctx, ]} } 二、離線腳本和多app嵌套時:能夠在棧中放入多個數據,在任何狀況下均可以獲取到當前app請求對應的響應 with app01.app_context(): print(current_app) with app02.app_context(): print(current_app) print(current_app)
g 至關於一次請求的全局變量,能夠對g進行相應的擴展(將用戶的權限賦值給g; 認證,將登錄用戶的標識賦值給g)
-請求進來時,將g和app封裝爲一個APPContext類,在經過LocalStack將Appcontext放入Local中,
-視圖函數中,經過localproxy-->偏函數-->LocalStack-->local中取值,
-響應時將local中的g數據刪除:
RequestContext
AppContext
LocalStack
Local
LocalProxy
#對url進行處理和分發 from flask import Flask from werkzeug.wsgi import DispatcherMiddleware from werkzeug.serving import run_simple app01 = Flask('app01') app02 = Flask('app02') @app01.route('/login') def login(): return 'app01.login' @app02.route('/index') def index(): return 'app02.index' # 訪問"login"--->"http://localhost:5000/login" # 訪問"index"--->"http://localhost:5000/app02/index" dm = DispatcherMiddleware(app01, { '/app02': app02, }) if __name__ == '__main__': run_simple('localhost', 5000, dm)
orm關係對象映射
sql語句編寫較爲複雜,開發效率低,可是查詢速度快
orm操做方便,可提升開發效率,相對sql語句查詢速度低
一、直接建立session,多線程時須要爲每一個線程建立session
二、基於scoped_session建立 session = scoped_session(Session) ,多線程時內部會自動爲每一個線程建立session (好像是threading.local)
Local中可使用協程中的惟一標識做爲棧中的key,粒度更細
信號
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') # 請求上下文push時執行 appcontext_popped = _signals.signal('appcontext-popped') # 請求上下文pop時執行 message_flashed = _signals.signal('message-flashed') # 調用flask在其中添加數據時,自動觸發
class Stack(object): def __init__(self,size): self.stack=[] self.size=size def isfull(self): """ 判讀棧空 :return: """ if len(self.stack)==0: return True else: return False def isempty(self): """ 判斷棧滿 :return: """ if len(self.stack)==self.size: return False else: return True def top(self,*args): if not self.isempty(): raise Exception("已滿") else: self.stack.append(*args) def pop(self): if self.isfull(): raise Exception("已空") else: self.stack.pop() if __name__=="__main__": s=Stack(4) # for i in range(7): # s.top(i) # print(s.stack) for j in range(6): s.pop() print(s.stack)
import heapq class PriorityQueue(object): #實現一個優先級隊列,每次pop優先級最高的元素 def __init__(self): self.queue = [] self.index = 0 def push(self,item,priority): # 將priority和index結合使用,在priority相同的時候比較index,pop先進入隊列的元素 heapq.heappush(self.queue,(priority,self.index,item)) self.index += 1 def pop(self): return heapq.heappop(self.queue)[-1] if __name__ == '__main__': pqueue = PriorityQueue() pqueue.push('d',2) pqueue.push('f',3) pqueue.push('a',6) pqueue.push('s',4) pqueue.push('cao',9) print(pqueue.queue) print(pqueue.pop()) print(pqueue.queue) print(pqueue.pop()) print(pqueue.pop()) print(pqueue.pop())
異步非阻塞+websocket
異步非阻塞本質:裝飾器+Futrue
目標:經過一個線程處理N個併發請求。 使用支持tornado異步非阻塞的單獨模塊: MySQL Redis SQLALchemy Tornado異步非阻塞本質:
視圖函數yield一個futrue對象,
futrue對象默認: self._done = False ,請求未完成 self._result = None ,請求完成後返回值,用於傳遞給回調函數使用。 tornado就會一直去檢測futrue對象的_done是否已經變成True。 若是IO請求執行完畢,自動會調用future的set_result方法: self._result = result self._done = True
如: <link href="{{static_url("commons.css")}}" rel="stylesheet" />
static_url()自動去配置的路徑下找commons.css文件
torndb、mysqldb
Tornado-redis
web聊天室,在線投票,處理高併發任務
redis它是將數據放在緩存中的,相比將數據放入到硬盤上,他的訪問速度更快,而且能夠將緩存中的數據定時更新到硬板中,同時增長了數據的安全性,它支持五大數據類型,字符串、數組、哈希、集合、有序集合
1)、存儲方式 Memecache把數據所有存在內存之中,斷電後會掛掉,數據不能超過內存大小。 Redis有部份存在硬盤上,這樣能保證數據的持久性。 2)、數據支持類型 Memcache只支持字符串類型 Redis支持五大數據類型
3)持久化、高可用、分佈式
redis支持數據持久化(RDB,AOF)、高可用、分佈式
memcached不支持,本身搭建
應用場景:
字符串:rest farmework中的session, open_session.setex() save_session.get()
列表 消息隊列、頻率、調度器、
哈希 購物車
集合 url去重
有序集合 調度器的有優先級,排行榜
-購物車信息(商品設置超時時間)
-django-session
-rest frmawork 中的訪問頻率
-基於flask的websocket作的實時投票,使用redis作消息隊列
-scrapy框架
-URL去重 set()
-調度器 先進先出、後進先出、優先級
-pipelines 相似於生產者消費者模型
-起始url 將起始url放入緩存中
-商品的熱點信息
-計數器 將修改的數據放入redis中再定時更新到數據庫中
-排序 有序集合
0-15個庫,默認的db0單庫
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": "密碼", } }, } SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置
目的:是對redis作高可用,爲每個redis實例建立一個備份稱爲slave,主redis進行寫操做,從redis作讀操做,而且讓主和從之間進行數據同步,
優勢:
- 性能提升,從分擔了主的壓力。保證了數據的安全性
- 高可用,一旦主redis掛了,直接讓從代替主。
存在問題:當主掛了以後,須要人爲操做將從變成主。
數據同步機制:
主從剛剛鏈接的時候,進行全量同步;全同步結束後,進行增量同步。固然,若是有須要,slave 在任什麼時候候均可以發起全量同步。
redis 策略是,不管如何,首先會嘗試進行增量同步,如不成功,要求從機進行全量同步。
一、自動在主從redis之間進行切換
二、檢測主從中 主是否掛掉,且超過一半的sentinel檢測到主掛掉以後才進行切換將從redis變爲主redis。
三、若是主修復好了,再次啓動時候,會變成從。
集羣方案: - redis cluster 官方提供的集羣方案。 - codis,豌豆莢技術團隊。 - twemproxy,Twiter技術團隊。
-程序 (一致性哈希 hash-ring) redis cluster的原理? - 基於分佈式集羣來完成。(不一樣任務交給不一樣的redis處理) - redis將全部能放置數據的地方建立了 16384 個哈希槽。 - 若是設置集羣的話,就能夠爲每一個實例分配哈希槽: - 192.168.1.20【0-5000】 - 192.168.1.21【5001-10000】 - 192.168.1.22【10001-16384】 - 之後想要在redis中寫值時, set k1 123 將k1經過crc16的算法,將k1轉換成一個數字。而後再將該數字和16384求餘,若是獲得的餘數 3000,那麼就將該值寫入到 192.168.1.20 實例中。
實現redis分佈式集羣
一致性哈希:是一種分佈式算法,將任務均勻的分佈到不一樣的服務器上,經常使用於負載均衡,
hash_ring 將key利用crc32------>數字------>數字和服務器數取餘-------->放入服務器對應的數值區間
RDB持久化 -每隔一段時間對redis進行一次持久化(基於時間點快照的方式,複用方式進行數據持久化) -效率較高,數據不完整,安全性不高 AOF持久化
-把全部命令保存起來,若是想到從新生成到redis,那麼就要把命令從新執行一次。
-效率相對較低,安全性較高
.一、MySQL ⾥裏里有 2000w 數據,redis 中只存 20w 的數據,如何保證 redis 中都是熱點數據
voltile-lru: 從已設置過時時間的數據集(server.db[i].expires)中挑選最近頻率最少數據淘汰 volatile-ttl: 從已設置過時時間的數據集(server.db[i].expires)中挑選將要過時的數據淘汰 volatile-random:從已設置過時時間的數據集(server.db[i].expires)中任意選擇數據淘汰 allkeys-lru: 從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰 allkeys-random: 從數據集(server.db[i].dict)中任意選擇數據淘汰 no-enviction(驅逐):禁止驅逐數據
單太redis時,可使用watch
對多臺redis進行操做時,加鎖並設置超時時間,保證在此期間只有你一我的對redis操做,
----流程
- 寫值{key:"sfdfff"}加鎖並設置超時時間 - 超過一半的redis實例設置成功,就表示加鎖完成。
-解鎖 執行lua腳本,用key檢測每一個redis中是否有次key,有則刪除
- 使用:安裝redlock-py from redlock import Redlock Redlock算法 dlm = Redlock( [ {"host": "localhost", "port": 6379, "db": 0}, {"host": "localhost", "port": 6379, "db": 0}, {"host": "localhost", "port": 6379, "db": 0}, ] ) # 加鎖,acquire my_lock = dlm.lock("my_resource_name",10000) if my_lock: # J進行操做 # 解鎖,release dlm.unlock(my_lock) else: print('獲取鎖失敗')
監聽一個數據,下次提交時,若是中間有人對此數據修改,則會報錯
- 經過redis的watch實現 import redis conn = redis.Redis(host='127.0.0.1',port=6379) # conn.set('count',1000) val = conn.get('count') print(val) with conn.pipeline(transaction=True) as pipe: # 先監視,本身的值沒有被修改過 conn.watch('count') # 事務開始 pipe.multi() old_count = conn.get('count') count = int(old_count) print('如今剩餘的商品有:%s',count) input("問媳婦讓不讓買?") pipe.set('count', count - 1) # 執行,把全部命令一次性推送過去 pipe.execute()
將一部分執行命令進行批量操做,
import redis pool = redis.ConnectionPool(host='10.211.55.4', port=6379) conn = redis.Redis(connection_pool=pool) # pipe = r.pipeline(transaction=False) pipe = conn.pipeline(transaction=True) # 開始事務 pipe.multi() pipe.set('name', 'alex') pipe.set('role', 'sb') pipe.lpush('roless', 'sb') # 提交 pipe.execute()
發佈者: import redis conn = redis.Redis(host='127.0.0.1',port=6379) conn.publish('104.9MH', "hahahahahaha") 訂閱者: import redis conn = redis.Redis(host='127.0.0.1',port=6379) pub = conn.pubsub() pub.subscribe('104.9MH') while True: msg= pub.parse_response() print(msg)
發佈訂閱:只要發佈者發佈任務則全部訂閱者都會接受到此任務。
消息隊列:隊列中放一個任務,則只有一個進程取任務
發佈訂閱和簡單的消息隊列區別在於,發佈訂閱會將消息發送給全部的訂閱者,而消息隊列中的數據被消費一次便消失。
因此,RabbitMQ實現發佈和訂閱時,會爲每個訂閱者建立一個隊列,而發佈者發佈消息時,會將消息放置在全部相關隊列中。
在線投票
import heapq class PriorityQueue(object): """實現一個優先級隊列,每次pop優先級最高的元素""" def __init__(self): self._queue = [] self._index = 0 def push(self,item,priority): # 將priority和index結合使用,在priority相同的時候比較index,pop先進入隊列的元素 heapq.heappush(self._queue,(-priority,self._index,item)) self._index += 1 def pop(self): return heapq.heappop(self._queue)[-1] if __name__ == '__main__': pqueue = PriorityQueue() pqueue.push('d',2) pqueue.push('f',3) pqueue.push('a',6) pqueue.push('s',2) print(pqueue.pop()) print(pqueue.pop()) print(pqueue.pop()) print(pqueue.pop())
def list_scan_iter(name,count=3): start = 0 while True: result = conn.lrange(name, start, start+count-1) start += count if not result: break for item in result: yield item for val in list_scan_iter('num_list'): print(val)
列表、集合、有序集合使用scan_iter
keys(pattern="*") # 根據模型獲取redis的name # 更多: # KEYS * 匹配數據庫中全部 key 。 # KEYS h?llo 匹配 hello , hallo 和 hxllo 等。 # KEYS h*llo 匹配 hllo 和 heeeeello 等。 # KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
一、Http協議是基於tcp協議之上的短鏈接、無狀態請求,規定數據之間\r\n分割,請求頭與請求體\r\n\r\n分割
二、請求頭:Host Content-Type User_Agent method referer Date cookie
三、狀態碼
成功 200 成功 202 服務器已接受請求,但還沒有處理 重定向: 301 永久重定向 302 臨時重定向 客戶端: 400 客戶端請求有語法錯誤,不能被服務器所理解 401 請求未經受權,這個狀態代碼必須和WWW-Authenticate報頭域一塊兒使用 403 服務器收到請求,可是拒絕提供服務 404 請求資源不存在,eg:輸入了錯誤的URL 服務器: 500 服務器發生不可預期的錯誤 503 服務器當前不能處理客戶端的請求,一段時間後可能恢復正常
四、請求方式
1 GET 請求指定的頁面信息,並返回實體主體。 2 HEAD 相似於get請求,只不過返回的響應中沒有具體的內容,用於獲取報頭 3 POST 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會致使新的資源的創建和/或已有資源的修改。 4 PUT 從客戶端向服務器傳送的數據取代指定的文檔的內容。 5 DELETE 請求服務器刪除指定的頁面。 6 CONNECT HTTP/1.1協議中預留給可以將鏈接改成管道方式的代理服務器。 7 OPTIONS 容許客戶端查看服務器的性能。 8 TRACE 回顯服務器收到的請求,主要用於測試或診斷。
Http: 80端
https: 443端口
- 自定義證書
- 服務端:建立一對證書
- 客戶端:必須攜帶證書
- 購買證書
- 服務端: 建立一對證書,-將公鑰交給機構
- 客戶端: 去機構獲取證書,數據加密後發給我們的服務單
一、websocket協議是基於http的協議之上的,只是客戶端與服務端創建鏈接以後將再也不斷開,實現服務端向客戶端主動發送請求
-進行數據通訊前先進行校驗(握手)
-發送的數據都是加密的
二、websocket本質
1、建立一個創建鏈接以後不斷開的socket 2、建立鏈接(握手) -客戶端向服務端發送請求 -服務端獲取請求頭中的Sec-WebSocket-key的值,將此值+magic_string(魔法字符串)進行hashlib和base64加密 -構造響應頭,裏面包含Sec-WebSocket-Accept: 加密後的值 -返送給客戶端 -客戶端再拿到加密的數據,解密進行驗證 3、鏈接創建成功後:創建雙工通道(同一時間,便可發送數據也可接受數據),進行數據通訊 -發送的數據都是加密的,解密後,根據payload_len的值獲取內容(payload_len的值至關於報頭) -payload_len <=125 -payload_len ==126 -payload_len ==127 -將獲取的內容分爲 -mask_key -數據 根據mask_key和數據進行位運算,最後解析出數據
三、websocket的應用----但是實現客戶端實時監聽服務端的數據變化的操做
如:實時消息推送
- 輪詢 優勢:代碼簡單; 缺點:請求次數多,服務器壓力大,消息延遲。 - 長輪詢 優勢:實時接收數據,兼容性好; 缺點:請求次數相對輪詢減小。 - websocket 優勢:代碼簡單,再也不反覆建立鏈接。 缺點:兼容性差,不支持IE。
相同點:
一、websocket和http都是基於TCP協議的
二、都是屬於應用層的
不一樣點:
聯繫:
一、WebSocket在創建握手時,數據是經過HTTP傳輸的。可是創建以後,在真正傳輸時候是不須要HTTP協議的。
- django: channel
- flask: gevent-websocket
- tornado: 內置
一、輪詢
經過定時器讓客戶端每隔幾秒就向服務端發送一次請求
二、長輪詢
客戶端向服務端發送一次請求,瀏覽器會將次請求夯住一段時間,若是有數據返回則當即響應,若是在此時間內沒有數據返回則斷開鏈接,客戶端再次發送請求
ps:利用queue和redis實現夯住請求
三、輪詢的目的
由於http請求是短鏈接無狀態的,服務端沒法實時向客戶端發送請求
因此客戶端能夠利用輪詢和長輪詢向服務端實時發送請求
一個網站能夠兼容多個終端(根據分辨率不一樣自動匹配)
@media (min-width: 768px){ .pg-header{ background-color: green; } } @media (min-width: 992px){ .pg-header{ background-color: pink; } }
Jquery
BootStrap
vue.js Angular.js React.js
ajax:異步請求+局部刷新
jquery:$.ajax()
xml : var xmlHttp = new XMLHttpRequest()
vuex維護了一個「全局變量" 基於vue_cookies能夠作用戶登陸、註銷
使用Vuex只需執行 Vue.use(Vuex),並在Vue的配置中傳入一個store對象的示例(vue.store)
能夠作權限
相似於ajax
v-html 插入html
v-text 在元素中插入值
v-if v-else
v-show
v-for
v-on 監聽
v-bind 綁定
v-model 把input的值和變量綁定了,實現了數據和視圖的雙向綁定
自定義一個script標籤,調用回調函數, 後端返回一個函數()
jsop只能get請求
添加響應頭
https://www.cnblogs.com/caochao-/articles/8823080.html
merge:會將不一樣分支的提交合併成一個新的節點,以前的提交分開顯示,注重歷史信息、能夠看出每一個分支信息,基於時間點 , 遇到衝突,手動解決,再次提交
rebase:將兩個分支的提交結果融合成線性,不會產生新的節點,注重開發過程, 遇到衝突,手動解決,繼續操做
1、大家公司的代碼review分支怎麼作?誰來作? 答:組長建立review分支,咱們小功能開發完以後,合併到review分支 交給老大(小組長)來看, 你組長不開發代碼嗎? 他開發代碼,可是它只開發核心的東西,任務比較少。 或者抽出時間,咱們一塊兒作這個事情 2、大家公司協同開發是怎麼協同開發的? 每一個人都有本身的分支,階段性代碼完成以後,合併到review,而後交給老大看
在命令行中,使用「git tag –a tagname –m 「comment」能夠快速建立一個標籤。須要注意,命令行建立的標籤只存在本地Git庫中,還須要使用Git push –tags指令發佈到TFS服務器的Git庫中
gitlab是公司本身搭建的項目代碼管理平臺
gitlab是公司本身搭建的項目託管平臺
設置哪些文件不須要添加到版本管理中 (好比Python的.pyc文件和一些包含密碼的配置文件等)
敏捷開發:是一種以人爲核心、迭代、按部就班的開發方式。
它並非一門技術,而是一種開發方式,也就是一種軟件開發的流程。它會指導咱們用規定的環節去一步一步完成項目的開發。由於它採用的是迭代式開發,因此這種開發方式的主要驅動核心是人
Jenkins 是一個可擴展的持續集成引擎。
主要用於:
nginx+uwsgi+django
爲了預防消息丟失,rabbitmq提供了ack,即工做進程在收到消息並處理後,發送ack給rabbitmq,告知rabbitmq這時候能夠把該消息從隊列中刪除了。若是工做進程掛掉 了,rabbitmq沒有收到ack,那麼會把該消息 從新分發給其餘工做進程。不須要設置timeout,即便該任務須要很長時間也能夠處理。
ack默認是開啓的,工做進程顯示指定了no_ack=True
一、建立隊列和發送消息時將設置durable=Ture,若是在接收到消息尚未存儲時,消息也有可能丟失,就必須配置publisher confirm
channel.queue_declare(queue='task_queue', durable=True)
二、返回一個ack,進程收到消息並處理完任務後,發給rabbitmq一個ack表示任務已經完成,能夠刪除該任務
三、鏡像隊列:將queue鏡像到cluster中其餘的節點之上。在該實現下,若是集羣中的一個節點失效了,queue能自動地切換到鏡像中的另外一個節點以保證服務的可用性
默認消息隊列裏的數據是按照順序被消費者拿走,例如:消費者1 去隊列中獲取 奇數 序列的任務,消費者2 去隊列中獲取 偶數 序列的任務。
channel.basic_qos(prefetch_count=1) 表示誰來誰取,再也不按照奇偶數排列(同時也保證了公平的消費分發)
amqp協議中的核心思想就是生產者和消費者隔離,生產者從不直接將消息發送給隊列。
生產者一般不知道是否一個消息會被髮送到隊列中,只是將消息發送到一個交換機。
先由Exchange來接收,而後Exchange按照特定的策略轉發到Queue進行存儲。
同理,消費者也是如此。Exchange 就相似於一個交換機,轉發各個消息分發到相應的隊列中。
type=fanout 相似發佈者訂閱者模式,會爲每個訂閱者建立一個隊列,而發佈者發佈消息時,會將消息放置在全部相關隊列中
type=direct 隊列綁定關鍵字,發送者將數據根據關鍵字發送到消息exchange,exchange根據 關鍵字 斷定應該將數據發送至指定隊列。
type=topic 隊列綁定幾個模糊的關鍵字,以後發送者將數據發送到exchange,exchange將傳入」路由值「和 」關鍵字「進行匹配,匹配成功,則將數據發送到指定隊列。
發送者路由值 隊列中 old.boy.python old.* -- 不匹配 *表示匹配一個 old.boy.python old.# -- 匹配 #表示匹配0個或多個
celery是python開發的一個分佈式任務隊列模塊,自己本不支持消息傳遞,依賴於redis、rabbitmq(官方推薦)
一、當用戶觸發一個操做須要較長時間才能執行完成的任務時,就能夠交給Celery異步執行,執行完再返回給用戶。這段時間用戶不須要等待,提升了網站的總體吞吐量和響應時間。
二、定時任務,好比天天檢測一下大家全部客戶的資料,若是發現今天 是客戶的生日,就給他發個短信祝福
任務模塊 Task
包含異步任務和定時任務。其中,異步任務一般在業務邏輯中被觸發併發往任務隊列,而定時任務由 Celery Beat 進程週期性地將任務發往任務隊列。
消息中間件 Broker
Broker,即爲任務調度隊列,接收任務生產者發來的消息(即任務),將任務存入隊列。Celery 自己不提供隊列服務,官方推薦使用 RabbitMQ 和 Redis 等。
任務執行單元 Worker
Worker 是執行任務的處理單元,它實時監控消息隊列,獲取隊列中調度的任務,並執行它。
任務結果存儲 Backend
Backend 用於存儲任務的執行結果,以供查詢。同消息中間件同樣,存儲也可以使用 RabbitMQ, redis 和 MongoDB 等。
一、配置文件,設置beat_schedule
二、程序控制 經過 crontab 的對象
@shared_task爲全部的celery對象,建立任務
@app.task爲單個celery對象建立任務
獲取網站html或xml文本
將html或xml標籤進行解析
Selenium 是一個用於Web應用程序測試的工具,他的測試直接運行在瀏覽器上,模擬真實用戶,按照代碼作出點擊、輸入、打開等操做
爬蟲中使用他是爲了解決requests沒法解決javascript動態問題
爬蟲spiders中 yield item
raise DropItem()
實現了分佈式爬蟲,有url去重、調度器、數據持久化
廣度優先:先進先出(默認)有序集合
深度優先:先進後出
vitualenv 是一個獨立的python虛擬環境
如:當前項目依賴的是一個版本,可是另外一個項目依賴的是另外一個版本,這樣就會形成依賴衝突,而virtualenv就是解決這種狀況的,virtualenv經過建立一個虛擬化的python運行環境,將咱們所需的依賴安裝進去的,不一樣項目之間相互不干擾
能夠經過對項目目錄掃描,自動發現使用了那些類庫,而且自動生成依賴清單。
pipreqs ./ 生成requirements.txt
pylint
選擇、插入、
沒有
公司開發環境: 1. windows - 在windows上開發【坑】 - 代碼部署在linux :centos 2. 雙系統 - windows - linux: ubuntu+桌面版 - linux: centos+桌面版 - 代碼部署在linux :centos 3. mac - linux:mac - 代碼部署在linux :centos 4. vim開發 - 經過vim在:centos - 代碼部署在linux :centos
PV:訪問量, 即頁面瀏覽量或點擊量,衡量網站用戶訪問的網頁數量;在必定統計週期內用戶每打開或刷新一個頁面就記錄1次,屢次打開或刷新同一頁面則瀏覽量累計。
UV:獨立訪客,統計1天內訪問某站點的用戶數(以cookie爲依據);訪問網站的一臺電腦客戶端爲一個訪客
QPS:每秒查詢率QPS是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準,在因特網上,做爲域名系統服務器的機器的性能常常用每秒查詢率來衡量
TPS:是軟件測試結果的測量單位。一個事務是指一個客戶機向服務器發送請求而後服務器作出反應的過程。客戶機在發送請求時開始計時,收到服務器響應後結束計時,以此來計算使用的時間和完成的事務個數。
Supervisor是一個進程管理工具
用途就是有一個進程須要每時每刻不斷的跑,可是這個進程又有可能因爲各類緣由有可能中斷。當進程中斷的時候我但願能自動從新啓動它,此時,用到Supervisor的fork/exec的方式
將傳輸的數據加密並壓縮,客戶端提供了口令驗證和密鑰驗證
stackoverflow
git
知乎
思否
bing
python之禪
碼農翻身
django官方文檔
rabbiitMQ官方文檔
django rest framework 官方文檔
opentack
docker
人工智能API,實現小功能。智能語音
區塊鏈