1. django和flask框架的區別?
django:大而全的全的框架,重武器;內置很多組件:ORM、admin、Form、ModelForm、中間件、信號、緩存、csrf等
flask: 微型框架、可擴展強,如果開發簡單程序使用flask比較快速,如果實現負責功能就需要引入一些組件:flask-session/flask-SQLAlchemy/wtforms/flask-migrate/flask-script/blinker這兩個框架都是基于wsgi協議實現的,默認使用的wsgi模塊不一樣。還有一個顯著的特點,他們處理請求的方式不同:django: 通過將請求封裝成Request對象,再通過參數進行傳遞。flask:通過上下文管理實現。延伸:- django組件 - flask組件,用途 - wsgi- 上下文管理
2. wsgi作用??
wsgi ? ?》》點我
新知識
web服務網關接口,一套協議。 實現了wsgi協議的模塊本質上就是編寫了socket服務端,用來監聽用戶請求,如果有請求到來,則將請求進行一次封裝,然后將【請求】交給 web框架來進行下一步處理。目前接觸:wsgiref (dajngo)werkzurg (flask)uwsgi from wsgiref.simple_server import make_serverdef 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 = WSGIRequestdef __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
3. django 請求生命周期
a. wsgi, 創建socket服務端,用于接收用戶請求并對請求進行初次封裝。
b. 中間件,對所有請求到來之前,響應之前定制一些操作。
c. 路由匹配,在url和視圖函數對應關系中,根據當前請求url找到相應的函數。
d. 執行視圖函數,業務處理【通過ORM去數據庫中獲取數據,再去拿到模板,然后將數據和模板進行渲染】
e. 再經過所有中間件
f. 通過wsgi將響應返回給用戶。
圖
4. 中間件?
所有的請求做統一操作時,用中間件
中間件點我
所有方法:- process_request- process_view- process_template_response , 當視圖函數的返回值對象中有render方法時,該方法才會被調用。- process_response- process_excaption
?
?
5.中間件的應用:
?
- 登錄驗證,為什么:如果不適用就需要為每個函數添加裝飾器,太繁瑣。- 權限處理,為什么:用戶登錄后,將權限放到session中,然后再每次請求時需要判斷當前用戶是否有權訪問當前url,這檢查的東西就可以放到中間件中進行統一處理。- 還有一些內置: - csrf,為什么- session,為什么- 全站緩存 ,為什么- 另外,還有一個就是處理:跨域 (前后端分離時,本地測試開發時使用的。)
6. csrf原理
目標:防止用戶直接向服務端發起POST請求。
方案:先發送GET請求時,將token保存到(csrftoken保存位置):cookie、Form表單中(保存位置隱藏的input標簽),以后再發送請求時只要攜帶過來即可。
問題:如何向后臺發送POST請求?
新知識
?
form表單提交:<form method="POST">{% csrf_token %}<input type='text' name='user' /><input type='submit' /></form>ajax提交:$.ajax({url:'/index',type:'POST',data:{csrfmiddlewaretoken:'{{ csrf_token }}',name:'alex'}})前提:引入jquery + 引入jquery.cookie (此模塊可以完成從cookie中取出csrftoken)$.ajax({url: 'xx',type:'POST',data:{name:'oldboyedu'},headers:{X-CSRFToken: $.cookie('csrftoken') }, #在請求頭中加上這個信息 注意名字必須是 X-CSRFToken:dataType:'json', // arg = JSON.parse('{"k1":123}')success:function(arg){}})
?
?
<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> //導入jquery.cookie<script>$.ajaxSetup({ //在以后每一個發送ajax請求之前,每次發送之前 都會執行該函數
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>
7. 視圖函數
FBV:def index(request):pass CBV: class IndexView(View):# 如果是crsf相關,必須放在此處def dispach(self,request):# 通過反射執行post/get @method_decoretor(裝飾器函數)def get(self,request):passdef post(self,request):pass 路由:IndexView.as_view()
FBV和CBV的區別?
- 沒什么區別,因為他們的本質都是函數。CBV的.as_view()返回的view函數,view函數中調用類的dispatch方法,在dispatch方法中通過反射執行get/post/delete/put等方法。
- CBV比較簡潔,GET/POST等業務功能分別放在不同get/post函數中。FBV自己做判斷進行區分。
在cbv中加裝飾器:
1.裝飾器
from django.views import Viewfrom django.utils.decorators import method_decoratordef auth(func):def inner(*args,**kwargs):return func(*args,**kwargs)return innerclass UserView(View):@method_decorator(auth)def get(self,request,*args,**kwargs):
?
2.處理csrf的問題
from django.views.decorators.csrf import csrf_exemptfrom django.utils.decorators import method_decorator# 方式1 # @method_decorator(csrf_exempt,name="dispatch") class UserView(View):#方式二#也可以自定義以dispatch()方法@method_decorator(csrf_exempt) #加上這句就可以不驗證post請求的csrf內容def dispatch(self, request, *args, **kwargs):#寫上一個print 方法print('Hollow')#運行的內容繼承dispatch 接收返回值res=super(UserView, self).dispatch(request, *args, **kwargs)#將返回值返回return res#定義兩個類,get post這兩個def get(self,request):print('get11111')return HttpResponse('getOK')def post(self,request):return HttpResponse('postOK')
?
8. ORM?
a. 增刪改查
b. 常用
order_by
group_by
limit
練表/跨表
?
?
c. 靠近原生SQL?(如何在orm中執行原生sql)
?
- extradef extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)# 構造額外的查詢條件或者映射,如:子查詢 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 def raw(self, raw_query, params=None, translations=None, using=None):# 執行原生SQLmodels.UserInfo.objects.raw('select * from userinfo')# 如果SQL是其他表時,必須將名字設置為當前UserInfo對象的主鍵列名models.UserInfo.objects.raw('select id as nid,name as title 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)# 指定數據庫models.UserInfo.objects.raw('select * from userinfo', using="default")- 原生from django.db import connection, connectionscursor = connection.cursor() # cursor = connections['default'].cursor()cursor.execute("""SELECT * from auth_user where id = %s""", [1])row = cursor.fetchone() # fetchall()/fetchmany(..)
?
d. 高級一點
- F
- Q
- select_related
- prefech_related
e. 其他:
?


################################################################### PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET ###################################################################def all(self)# 獲取所有的數據對象def filter(self, *args, **kwargs)# 條件查詢# 條件可以是:參數,字典,Qdef exclude(self, *args, **kwargs)# 條件查詢# 條件可以是:參數,字典,Qdef select_related(self, *fields)性能相關:表之間進行join連表操作,一次性獲取關聯的數據。model.tb.objects.all().select_related()model.tb.objects.all().select_related('外鍵字段')model.tb.objects.all().select_related('外鍵字段__外鍵字段')def prefetch_related(self, *lookups)性能相關:多表連表操作時速度會慢,使用其執行多次SQL查詢在Python代碼中實現連表操作。# 獲取所有用戶表# 獲取用戶類型表where id in (用戶表中的查到的所有用戶ID)models.UserInfo.objects.prefetch_related('外鍵字段')from django.db.models import Count, Case, When, IntegerFieldArticle.objects.annotate(numviews=Count(Case(When(readership__what_time__lt=treshold, then=1),output_field=CharField(),)))students = Student.objects.all().annotate(num_excused_absences=models.Sum(models.Case(models.When(absence__type='Excused', then=1),default=0,output_field=models.IntegerField())))def annotate(self, *args, **kwargs)# 用于實現聚合group by查詢from django.db.models import Count, Avg, Max, Min, Sumv = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))# SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)# SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)# SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1def distinct(self, *field_names)# 用于distinct去重models.UserInfo.objects.values('nid').distinct()# select distinct nid from userinfo 注:只有在PostgreSQL中才能使用distinct進行去重def order_by(self, *field_names)# 用于排序models.UserInfo.objects.all().order_by('-id','age')def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)# 構造額外的查詢條件或者映射,如:子查詢 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'])def reverse(self):# 倒序models.UserInfo.objects.all().order_by('-nid').reverse()# 注:如果存在order_by,reverse則是倒序,如果多個排序則一一倒序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 using(self, alias):指定使用的數據庫,參數為別名(setting中的設置)################################################### PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS ###################################################def raw(self, raw_query, params=None, translations=None, using=None):# 執行原生SQLmodels.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)# 指定數據庫models.UserInfo.objects.raw('select * from userinfo', using="default")################### 原生SQL ###################from django.db import connection, connectionscursor = connection.cursor() # cursor = connections['default'].cursor()cursor.execute("""SELECT * from auth_user where id = %s""", [1])row = cursor.fetchone() # fetchall()/fetchmany(..)def values(self, *fields):# 獲取每行數據為字典格式def values_list(self, *fields, **kwargs):# 獲取每行數據為元祖def dates(self, field_name, kind, order='ASC'):# 根據時間進行某一部分進行去重查找并截取指定內容# kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)# order只能是:"ASC" "DESC"# 并獲取轉換后的時間- year : 年-01-01- month: 年-月-01- day : 年-月-日models.DatePlus.objects.dates('ctime','day','DESC')def datetimes(self, field_name, kind, order='ASC', tzinfo=None):# 根據時間進行某一部分進行去重查找并截取指定內容,將時間轉換為指定時區時間# kind只能是 "year", "month", "day", "hour", "minute", "second"# order只能是:"ASC" "DESC"# tzinfo時區對象models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))"""pip3 install pytzimport pytzpytz.all_timezonespytz.timezone(‘Asia/Shanghai’)"""def none(self):# 空QuerySet對象##################################### METHODS THAT DO DATABASE QUERIES #####################################def aggregate(self, *args, **kwargs):# 聚合函數,獲取字典類型聚合結果from django.db.models import Count, Avg, Max, Min, Sumresult = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))===> {'k': 3, 'n': 4}def count(self):# 獲取個數def get(self, *args, **kwargs):# 獲取單個對象def create(self, **kwargs):# 創建對象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 get_or_create(self, defaults=None, **kwargs):# 如果存在,則獲取,否則,創建# defaults 指定創建時,其他字段的值obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})def update_or_create(self, defaults=None, **kwargs):# 如果存在,則更新,否則,創建# defaults 指定創建時或更新時的其他字段obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})def first(self):# 獲取第一個def last(self):# 獲取最后一個def in_bulk(self, id_list=None):# 根據主鍵ID進行查找id_list = [11,21,31]models.DDD.objects.in_bulk(id_list)def delete(self):# 刪除def update(self, **kwargs):# 更新def exists(self):
?
爬蟲相關:
- request/bs4- requests模塊- 參數:- url- headers - cookies - data - json - params - proxy- 返回值:- content- iter_content- text - encoding="utf-8"- cookie.get_dict()- bs4 - 解析:html.parser -> lxml - find - find_all- text - attrs- get - 其他:常見請求頭:- user-agent- host- referer- cookie - content-type 套路:- 先給你cookie,然后再給你授權。- 憑證輪詢+長輪詢- scrapy - 高性能相關,單線程并發發送Http請求- twisted- gevent - asyncio本質:基于IO多路復用+非阻塞的socket客戶端實現問題:異步非阻塞?問題:什么是協程?- scrapy框架- scrapy執行流程(包含所有組件)- 記錄爬蟲爬取數據深度(層級),request.meta['depth']- 傳遞cookie- 手動 - 自動:meta={'cookiejar':True}- 起始URL- 持久化:pipelines/items - 去重- 調度器- 中間件 - 下載中間件- agent- proxy - 爬蟲中間件- depth - 擴展+信號 - 自定義命令- scrapy-redis組件,本質:去重、調度器任務、pipeline、起始URL放到redis中。- 去重,使用的redis的集合。- 調度器,- redis列表- 先進先出隊列- 后進先出棧- redis有序集合- 優先級隊列PS:深度和廣度優先- pipelines- redis列表 - 起始URL - redis列表- redis集合補充:自定義encoder實現序列化時間等特殊類型:json.dumps(xx,cls=MyEncoder)- scrapy
?
?
?
?
?
?
?
登錄驗證
權限處理 ? (session中封裝了用戶的權限信息,根據取出的權限判斷用戶能看到什么,不能看到什么)
CSRF
session
cors跨域 ?: 解決方法
方法三
8. django的Form組件的作用?
- 對用戶請求的數據進行校驗
- 生成HTML標簽
問題:當form組件中從更新數據后下拉菜單中的數據,無法實時更新顯示
方法一:重寫構造方法
from django.shortcuts import render,HttpResponse from app01 import models def index(request):# return HttpResponse("...")return render(request,'index.html',{'x':123}) from django.forms import Form from django.forms import fields 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 ?并且給數據庫類中添加__str__類
from django.forms import Formfrom django.forms import fieldsfrom 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
?
orm中的方法(筆記中有新內容,復習下方法)
9.多數據庫的操作
將數據保存入指定的數據庫中去 ? 使用magrate來制定(傳統方式)
?
方法二 ?(添加一條數據)
如何指定使用那個數據庫?
?
?讀寫分離方法二
setting中的配置
代碼:
db_router.py中的代碼, ?此類中規定讀和寫用的數據庫


class Router1:def db_for_read(self, model, **hints):"""Attempts to read auth models go to auth_db."""return 'db1'def db_for_write(self, model, **hints):"""Attempts to write auth models go to auth_db."""return 'default'
settings.py中關于數據庫的配置


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, 'db1.sqlite3'),},}DATABASE_ROUTERS = ['db_router.Router1',]使用:models.UserType.objects.create(title='VVIP')result = models.UserType.objects.all()print(result)
?
方法二升級版:粒度更細的方法(粒度到每一張表的讀寫的配置)
?
?
?
問題:
app01中的表在 default ?數據庫創建
app02中的表在 db1 ? ? ? 數據庫創建
(如果有多個app想讓不同的app數據放到不同的數據庫)
代碼
# 第一步: python manage.py makemigraions # 第二步: app01中的表在default數據庫創建python manage.py migrate app01 --database=default# 第三步: app02中的表在db1數據庫創建python manage.py migrate app02 --database=db1
手動操作
(已知usertype是app01中的表)
(已知Users是app02中的表)
?
m1.UserType.objects.using('default').create(title='VVIP') m2.Users.objects.using('db1').create(name='VVIP',email='xxx')
?
自動操作
?
class Router1:def db_for_read(self, model, **hints):"""Attempts to read auth models go to auth_db."""if model._meta.app_label == 'app01':return 'default'else:return 'db1'def db_for_write(self, model, **hints):"""Attempts to write auth models go to auth_db."""if model._meta.app_label == 'app01':return 'default'else:return 'db1'
?
settings中的配置
DATABASE_ROUTERS = ['db_router.Router1',]
?
?
數據庫遷移時進行約束:
class Router1:def allow_migrate(self, db, app_label, model_name=None, **hints):"""All non-auth models end up in this pool."""if db=='db1' and app_label == 'app02':return Trueelif db == 'default' and app_label == 'app01':return Trueelse:return False# 如果返回None,那么表示交給后續的router,如果后續沒有router,則相當于返回Truedef db_for_read(self, model, **hints):"""Attempts to read auth models go to auth_db."""if model._meta.app_label == 'app01':return 'default'else:return 'db1'def db_for_write(self, model, **hints):"""Attempts to write auth models go to auth_db."""if model._meta.app_label == 'app01':return 'default'else:return 'db1'
?
?三: 類中有一個allow_migrate方法來管控是否允許某些app中數據進行遷移到對應的數據庫 ?(筆記代碼)
注意:如果返回None表示交給后續的router 如果后續沒有router 相當于返回的True(所以一般返回 TURE 或False 不要用None)
?
??
a. 什么是websocket?
websocket是給瀏覽器新建一套協議。協議規定:瀏覽器和服務端連接之后不斷開,以此可以完成:服務端向客戶端主動推送消息。
websocket協議額外做的一些前天操作:
- 握手,連接前進行校驗
- 發送數據加密
b. websocket本質
- socket
- 握手,魔法字符串+加密
- 加密,payload_len=127/126/<=125 -> mask key
?
18.序列化
內置的序列化只能處理queryset類型的數據
?19 admin &stark組件
20 Content
21
22 冪等性?
23 webservice是什么?
?