1. 簡述Http協議? - 超文本傳輸協議 - 特色: - 無狀態,請求響應以後,再次發起請求時,不認識。 - 短鏈接,一次請求和一次響應就斷開鏈接。 - 格式: - GET請求:輸入地址回車:https://passport.jd.com/new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F 請求由兩部分組成:請求頭和請求體,請求頭和請求體經過\r\n\r\n分割,請求頭和請求頭之間經過\r\n分割。 """GET /new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F http1.1\r\nUser-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36\r\nHost:jd.com\r\n\r\n""" 響應由兩部分組成:響應頭和響應體, b'HTTP/1.1 200 OK\r\nDate: Mon, 05 Nov 2018 01:15:31 GMT\r\nServer: Apache\r\nLast-Modified: Tue, 12 Jan 2010 13:48:00 GMT\r\nETag: "51-47cf7e6ee8400"\r\nAccept-Ranges: bytes\r\nContent-Length: 81\r\nCache-Control: max-age=86400\r\nExpires: Tue, 06 Nov 2018 01:15:31 GMT\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\n\r\n <html><head> .... </html>' - POST請求: 請求由兩部分組成:請求頭和請求頭 """POST /new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F http1.1\r\nUser-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36\r\nHost:jd.com\r\n\r\nusername=haoxu666&password=123""" 響應: b'HTTP/1.1 200 OK\r\nDate: Mon, 05 Nov 2018 01:15:31 GMT\r\nServer: Apache\r\nLast-Modified: Tue, 12 Jan 2010 13:48:00 GMT\r\nETag: "51-47cf7e6ee8400"\r\nAccept-Ranges: bytes\r\nContent-Length: 81\r\nCache-Control: max-age=86400\r\nExpires: Tue, 06 Nov 2018 01:15:31 GMT\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\n\r\n用戶名或密碼錯誤' 2. 你瞭解的請求頭都有什麼? - User-Agent,設備信息。 - Host,當前訪問的主機名稱。 - referrer,作防盜鏈。 - Content-Type: .... 3. 你瞭解的請求方式有哪些? - GET/POST/PUT/PATCH/DELETE/OPTIONS/HEAD/TRACE 4. django請求的生命週期/瀏覽器上輸入 http://www.oldboyedu.com 地址回車發生了什麼? - 瀏覽器輸入:http://www.oldboyedu.com 回車 - DNS解析,將域名解析成IP。 - 瀏覽器(socket客戶端),根據IP和端口(80)建立鏈接,發送請求。 - 服務端接收請求 - 實現了wsgi協議的模塊,如:wsgiref接收到用戶請求。 - 而後將請求轉交給django的中間件,執行中間件的process_request(process_view)。 - 路由系統進行路由匹配。 - 匹配成功執行視圖函數,視圖函數進行業務處理(ORM操做數據+模板渲染) - 交給中間件的process_response方法 - wsigref的socket.send,將結果返回給瀏覽器。 - 斷開socket鏈接。 - 瀏覽器斷開鏈接。 詳細:見django請求生命週期圖 5. 什麼是wsgi? wsgi,web服務網關接口,他是一套協議。 實現wsgi協議有: - wsgiref - uwsgi 實現wsgi協議的全部的模塊本質:socket服務端。 6. django中間件的做用?應用場景? 中間件,能夠對全部請求進行批量操做。 應用場景: - 本身玩 - 記錄日誌 - IP黑名單 - 權限系統中的權限校驗 - 解決跨域:編寫一箇中間件,在中間件中定義一個process_response,添加一個響應頭(CORS,跨站資源共享) - 用戶登陸 - csrf_token驗證(django內置功能) 細節: - 5個方法:process_request/process_response + 3 - 執行流程 正常流程: - 全部process_request - 全部process_view - 全部process_response 非正常流程: - django 1.10及之後:平級返回 - django 1.10之前:找到最後的process_response - 寫代碼時,若是忘記方法名稱或方法參數個數,怎麼辦? - 任意導入一個源碼查看,如: # from django.middleware.common import CommonMiddleware MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] - 執行流程是如何實現的? 將中間件的相關方法添加到對應的 5個列表中,之後循環執行(順序、倒序) 源碼: class BaseHandler(object): def __init__(self): self._request_middleware = None self._view_middleware = None self._template_response_middleware = None self._response_middleware = None self._exception_middleware = None self._middleware_chain = None def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE (or the deprecated MIDDLEWARE_CLASSES). Must be called after the environment is fixed (see __call__ in subclasses). """ self._request_middleware = [] self._view_middleware = [] self._template_response_middleware = [] self._response_middleware = [] self._exception_middleware = [] if settings.MIDDLEWARE is None: warnings.warn( "Old-style middleware using settings.MIDDLEWARE_CLASSES is " "deprecated. Update your middleware and use settings.MIDDLEWARE " "instead.", RemovedInDjango20Warning ) handler = convert_exception_to_response(self._legacy_get_response) for middleware_path in settings.MIDDLEWARE_CLASSES: mw_class = import_string(middleware_path) try: mw_instance = mw_class() except MiddlewareNotUsed as exc: if settings.DEBUG: if six.text_type(exc): logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc) else: logger.debug('MiddlewareNotUsed: %r', middleware_path) continue if hasattr(mw_instance, 'process_request'): self._request_middleware.append(mw_instance.process_request) if hasattr(mw_instance, 'process_view'): self._view_middleware.append(mw_instance.process_view) if hasattr(mw_instance, 'process_template_response'): self._template_response_middleware.insert(0, mw_instance.process_template_response) if hasattr(mw_instance, 'process_response'): self._response_middleware.insert(0, mw_instance.process_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.insert(0, mw_instance.process_exception) else: handler = convert_exception_to_response(self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): middleware = import_string(middleware_path) try: mw_instance = middleware(handler) except MiddlewareNotUsed as exc: if settings.DEBUG: if six.text_type(exc): logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc) else: logger.debug('MiddlewareNotUsed: %r', middleware_path) continue if mw_instance is None: raise ImproperlyConfigured( 'Middleware factory %s returned None.' % middleware_path ) if hasattr(mw_instance, 'process_view'): self._view_middleware.insert(0, mw_instance.process_view) if hasattr(mw_instance, 'process_template_response'): self._template_response_middleware.append(mw_instance.process_template_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.append(mw_instance.process_exception) handler = convert_exception_to_response(mw_instance) # We only assign to this when initialization is complete as it is used # as a flag for initialization being complete. self._middleware_chain = handler - 根據字符串的形式導入模塊 + 根據反射找到模塊中的成員 總結: 特色: - 全部請求都要經過中間件 - 5個方法 - 5個方法的執行流程 - 正常 - 不正常(版本區別) 應用場景: - 本身玩: - IP黑名單限制 - 日誌 - 工做場景: - 權限控制 - 跨域 - 登陸 - CSRF 相關知識點: - 流程實現原理:列表+列表翻轉 - 根據字符串的形式導入模塊+反射 做業: 1. django程序,用戶請求到來後將用戶用戶的 User-Agent 寫入到日誌中(logging模塊) 要求: - 經過源碼看其中有哪些方法和參數; # from django.middleware.common import CommonMiddleware - 在request對象中找 User-Agent 請求頭對應的值。 - logging模塊寫入日誌。 7. 路由系統 本質:保存url和函數的對應關係。 相關知識點: 示例1: url(r'^index/', views.index), def index(request): return HttpResponse('...') 示例2: url(r'^user/edit/(\d+)/$', views.user_edit), def user_edit(request,nid): return HttpResponse('...') 示例3: url(r'^crm/', include('app01.urls')) from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^order/', views.order), url(r'^center/', views.center), ] def order(request): return HttpResponse('...') def center(request): return HttpResponse('...') 示例4:根據name別名反向生成URL urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index,name='index'), url(r'^user/edit/(\d+)/$', views.user_edit,name='user_edit'), url(r'^crm/', include('app01.urls')), ] urlpatterns = [ url(r'^order/', views.order,name='order'), url(r'^center/', views.center,name='center'), ] 反向生成: index_url = reverse('index') user_edit_url = reverse('user_edit',args=('999',)) index_url = reverse('order') index_url = reverse('center') 示例5:根據 namespace + name 別名反向生成URL urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index,name='index'), url(r'^user/edit/(\d+)/$', views.user_edit,name='user_edit'), url(r'^crm/', include('app01.urls',namespace='crm')), ] urlpatterns = [ url(r'^order/', views.order,name='order'), url(r'^center/', views.center,name='center'), ] 視圖中反向生成: index_url = reverse('index') user_edit_url = reverse('user_edit',args=('999',)) index_url = reverse('crm:order') index_url = reverse('crm:center') 在模板中反向生成: {% url 'index' %} {% url 'user_edit' 999 %} {% url 'crm:order' %} {% url 'crm:center' %} 補充:公司項目從路由開始看,可能你看到的是這樣。 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index,name='index'), url(r'^user/edit/(\d+)/$', views.user_edit,name='user_edit'), url(r'^crm/', include('app01.urls',namespace='crm')), ] urlpatterns += [ url(r'^xxxx/', views.index), ] 8. 什麼是MVC、MTV? MVC, Model View Controller MTV, Model Template View 9. FBV和CBV FBV,寫函數進行處理業務邏輯。 CBV,寫類進行處理業務邏輯。 本質上FBV和CBV都是同樣的,由於url對應都是一個函數。 url(r'^order/', views.order,name='order'), # 1. 對應order函數;2.一旦請求到來,當即執行order函數 url(r'^center/', views.CenterView.as_view(),name='center'), # 1. url對應 views.CenterView.as_view()會返回一個view函數;2. 請求到來以後,當即執行view函數,view由會觸發dispatch方法、dispatch會根據method不一樣根據反射執行get/post/delete...的方法。 推薦: 業務邏輯,FBV(簡單)。 restful api,CBV。 10. 現象:兩個系統之間進行相互數據傳輸,李超向講師機發送POST請求,但講師機的request.POST中沒有獲取到數據,多是由於什麼? 1. csrf_token from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt def api(request): """ 爲李超提供的API接口 :param request: :return: """ print(request.POST) return HttpResponse('...') 實例代碼: 李超.py: import requests response = requests.post('http://127.0.0.1:8000/crm/api/',data={'user':'alex','pwd':'dsb'}) print(response.text) Http請求格式: """POST /crm/api/ http\1.1\r\nhost:..\r\nContent-Type:application/x-www-form-urlencoded .....\r\n\r\nuser=alex&pwd=dsb""" django服務端: from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt def api(request): """ 爲李超提供的API接口 :param request: :return: """ print(request.POST) return HttpResponse('...') 2. request.POST解析時,有限制。 李超.py import requests response = requests.post('http://127.0.0.1:8000/crm/api/',json={'user':'alex','pwd':'dsb'}) print(response.text) Http請求格式: """POST /crm/api/ http\1.1\r\nhost:..\r\nContent-Type:application/json .....\r\n\r\n{'user':'alex','pwd':'dsb'}""" django服務端: @csrf_exempt def api(request): """ 爲李超提供的API接口 :param request: :return: """ print(request.body) # 原生的請求體格式,有數據;(本身讀取body而後進行解析) print(request.POST) # 將原生的請求體轉換成 QueryDict對象,無數據。 return HttpResponse('...') 注意: request.POST 將原生的請求體轉換成 QueryDict對象,請求必須知足兩個條件才能轉換: - Content-Type:application/x-www-form-urlencoded - 數據格式: user=alex&pwd=dbs&xxx=123 若是不知足此條件,django獲取請求體時須要本身去request.body中獲取值。 總結: django獲取請求體 request.body request.POST是將請求體的數據轉換成了QueryDict對象。 11. 視圖函數的返回值 HttpResponse render 示例1: 視圖: def test(request): """ :param request: :return: """ return render(request,'test.html',{'k1':123}) test.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <div> <h1>{{ k1 }}</h1> <script> alert('{{ k1 }}'); </script> </div> </body> </html> 示例2: 視圖: def test(request): """ :param request: :return: """ return render(request,'test.html',{'k1':123}) test.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <div> <h1>{{ k1 }}</h1> # k1會被替換 <script src='/static/commons.js'></script> </div> </body> </html> commons.js alert('{{k1}}') # k1不會被替換,變量傳給視圖進行模板渲染,以後又向commons.js發了一次重定向請求,若是js代碼寫在html頁面的代碼中不進行重定向,是能夠被替換的 redirect 將要重定向的地址經過響應頭Location響應頭返回給瀏覽器。
今日內容: 路由分發的另一個方式: urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index,name='index'), url(r'^user/edit/(\d+)/$', views.user_edit,name='user_edit'), url(r'^crm/', include('app01.urls',namespace='crm')), url(r'^crm/', ([ url(r'^c1/', views.index), url(r'^c2/', ([ url(r'^c3/', views.index,name='n3'), # n1:n2:n3 url(r'^c4/', views.index), ],None,'n2')), ],None,'n1')), ] reverse('n3') # /crm/c2/n3/ reverse('n1:n3') # /crm/c2/n3/ 1. 模板 a. 模板查找順序 - 去根目錄下的templates文件夾中尋找 - 根據app的註冊順序,去每一個app的templates文件夾中尋找。 應用: 模板的替換 b. 模板繼承 c. include引入小組件 注意:若是模板中存在繼承和include,那麼模板引擎會將全部的模板拼接到一塊兒後再進行渲染(替換)。 d. 模板獲取索引 列表: users.0 字典: users.key e. 在模板中傳遞函數,自動加括號執行。 例如: def func(): return "999" def index(request): return render(request,'index.html',{'func':func}) 模板: <h1>函數:{{ func }}</h1> f. 模板中自定義函數 - simple_tag @register.simple_tag def func1(a1,a2,a3): """ 通常用於給頁面返回一個結果 :param a1: :param a2: :param a3: :return: """ return a1 + a2 + a3 <h1>調用simple_tag:{% func1 '戴綠' '郝旭' '阿段' %}</h1> - inclusion_tag @register.inclusion_tag('func2.html') def func2(a1,a2): """ 用於給頁面返回一個HTML代碼塊 :param a1: :param a2: :return: """ return {'data1':a1, 'data2':a2} <h1>調用inclusion_tag:{% func2 '戴綠' '郝旭' %}</h1> - filter @register.filter def func3(a1,a2): """ 能夠在if後面作條件,可是參數有限制(最多2個)。 :param a1: :param a2: :return: """ return a1 + a2 <h1>調用filter:{{ "戴綠"|func3:'郝旭' }}</h1> {% if "戴綠"|func3:'郝旭' %} <h1>asdf</h1> {% endif %} g. 模板中導入靜態文件 {% load staticfiles %} <img src="{% static '1.png' %}" alt=""> <img src="/static/1.png" alt=""> 禁止使用 贈送:1.10以前的版本模板路徑須要 TEMPLATES = ( os.path.join(BASE_DIR,'templates'), ) 2. ORM orm,關係對應映射。 類 -> 表 對象 -> 行 屬性 -> 字段 UserInfo.object model表類,對應數據庫中的表 <class 'django.db.models.manager.Manager'> obj = UserInfo.object.all() 查詢出來的queryset對象,裏面是數據庫對象,對應數據庫中的行 <class 'django.db.models.query.QuerySet'> obj.title obj.外鍵字段 #這是外鍵正向查詢 obj.小寫表名_set.all() #這是外鍵反向查詢 obj.多對多字段.all() #這是多對多關聯對象的正向查詢 obj.小寫多對多表名_set.all() #這是多對多關聯對象的反向查詢,由於多對多的本質就是兩個外鍵關係,因此是能夠用外鍵反向查詢的方法的 obj.一對一關聯字段名 #這是一對一關聯的正向查詢 obj.小寫一對一關聯表名 #這是一對一關聯的反向查詢 推薦博客:https://blog.csdn.net/weixin_40475396/article/details/79539608 操做表: 單表 class UserInfo(models.Model): """ 用戶表 """ username = models.CharField(verbose_name='用戶名', max_length=32) FK 基本操做: class Department(models.Model): """ 部門表 """ title = models.CharField(verbose_name='標題',max_length=32) class UserInfo(models.Model): """ 用戶表 """ username = models.CharField(verbose_name='用戶名', max_length=32) depart = models.ForeignKey(verbose_name='所屬部門',to="Department") on_delete: models.CASCADE,刪除部門,則將改部門下的員工所有刪除。 + 代碼判斷 models.DO_NOTHING,刪除部門,引起錯誤IntegrityError models.PROTECT,刪除部門,引起錯誤ProtectedError models.SET_NULL,刪除部門,則將改部門下的員工所屬部門ID設置爲空。(將FK字段設置爲null=True) models.SET_DEFAULT,刪除部門,則將改部門下的員工所屬部門ID設置默認值。(將FK字段設置爲default=2) models.SET,刪除部門,則將執行set對應的函數,函數的返回值就是要給改部門下員工設置的新的部門ID。 例如: def func(): models.Users....... return 10 class MyModel(models.Model): user = models.ForeignKey(to="User",to_field="id"on_delete=models.SET(func),) 方法: models.CASCADE, 刪除邏輯時,經過代碼判斷當前 「部門」 下是否有用戶。 models.SET_NULL,穩妥。 溝通以後在肯定。 db_constraint: depart = models.ForeignKey(verbose_name='所屬部門',to="Department",db_constraint=False) # 無約束,但可使用django orm的連表查詢。 models.UserInfo.objects.filter(depart__title='xxx') limit_choice_to 示例1: from django.db import models class Department(models.Model): """ 部門表 ID 名稱 1 教質部 2 Python學院 """ title = models.CharField(verbose_name='標題',max_length=32) class User(models.Model): """ 員工表 ID name depart_id 1 小雪 1 2 冰冰 1 3 小雨 1 4 太亮 2 5 金菊 2 """ name = models.CharField(verbose_name='員工名稱',max_length=32) depart = models.ForeignKey(to='Department') class ClassList(models.Model): """ 班級表 """ title = models.CharField(verbose_name='班級名稱', max_length=32) bzr = models.ForeignKey(to=User,limit_choices_to={'id__lt':4}) teacher = models.ForeignKey(to=User,limit_choices_to={'id__gte':4}) 示例2: from django.db import models class Department(models.Model): """ 部門表 ID 名稱 1 教質部 2 Python學院 """ title = models.CharField(verbose_name='標題',max_length=32) class User(models.Model): """ 員工表 ID name depart_id 1 小雪 1 2 太亮 2 3 小雨 1 4 冰冰 1 5 金菊 2 """ name = models.CharField(verbose_name='員工名稱',max_length=32) depart = models.ForeignKey(to='Department') class ClassList(models.Model): """ 班級表 """ title = models.CharField(verbose_name='班級名稱', max_length=32) bzr = models.ForeignKey(to=User,limit_choices_to={'depart__title':'教質部','id__gt':9}) teacher = models.ForeignKey(to=User,limit_choices_to={'depart__title':'Python學院'}) related_name 反向查找的字段。 示例: from django.db import models class Department(models.Model): """ 部門表 ID 名稱 1 教質部 2 Python學院 """ title = models.CharField(verbose_name='標題',max_length=32) class User(models.Model): """ 員工表 ID name depart_id 1 小雪 1 2 太亮 2 3 小雨 1 4 冰冰 1 5 金菊 2 """ name = models.CharField(verbose_name='員工名稱',max_length=32) depart = models.ForeignKey(to='Department') class ClassList(models.Model): """ 班級表 """ title = models.CharField(verbose_name='班級名稱', max_length=32) bzr = models.ForeignKey(to=User,related_name='x') teacher = models.ForeignKey(to=User,related_name='y') from app01 import models # 找班主任小雪帶的全部班級 obj = models.User.objects.filter(name='小雪').first() class_list = obj.x.all() for row in class_list: print(row.title) # 找老師金鑫帶的全部班級 obj1 = models.User.objects.filter(name='金鑫').first() class_list = obj1.y.all() for row in class_list: print(row.title) 補充: 對於FK,通常公司數據量和訪問量不大時,建立FK作約束。 數據量和訪問量巨大時,犧牲硬盤空間和程序員代碼量,依次來提供用戶訪問速度。(連表查詢速度會比單表查詢速度慢) M2M 自動建立第三張表(場景:關係表只有boy和girl的id): class Boy(models.Model): name = models.CharField(max_length=32) class Girl(models.Model): name = models.CharField(max_length=32) boy = models.ManyToManyField('Boy') 手動建立第三張表(場景:除了boy和girl的id之外,還須要其餘字段): class Boy(models.Model): name = models.CharField(max_length=32) class Girl(models.Model): name = models.CharField(max_length=32) class Boy2Girl(models.Model): b = models.ForeignKey(to='Boy') g = models.ForeignKey(to='Girl') class Meta: unique_together = ( ("b", "g"), ) O2O class UserInfo(models.Model): """ 1 好虛 2 戴綠 """ username = models.CharField(verbose_name='標題',max_length=32) class Blog(Model.Model): """ 1 好虛371 1 """ title = models.CharField(verbose_name='標題',max_length=32) a = models.OneToOneField(to='A') 應用場景: class userinfo: """ 老男孩全部員工 (130) """ name = 用戶名 email = 郵箱 ... class Admin: """ 給30我的開帳號(30),能夠登陸教務系統 """ username = 登陸用戶名 password ='密碼' user = o2o(userinfo) 補充:choices的應用場景。 例如:性別的數量不會隨着時間的推移而發生個數的變化。 # 不推薦 class Gender(models.Model): title = models.CharField(max_length=32) class Customer(models.Model): name = models.CharField(verbose_name='姓名',max_length=32) gender = models.ForeignKey(to='Gender') # 推薦 class Customer(models.Model): name = models.CharField(verbose_name='姓名',max_length=32) gender_choices = ( (1,'男'), (2,'女'), ) gender = models.IntegerField(choices=gender_choices) 數據庫優化手段,將固定數據放入內存代替放入數據庫。 操做數據: 增刪改查 class Department(models.Model): title = models.CharField(verbose_name='標題',max_length=32) class UserInfo(models.Model): name = models.CharField(verbose_name='員工名稱',max_length=32) depart = models.ForeignKey(to='Department') roles = models.ManyToManyField(to="Role") class Role(models.Model): title = models.CharField(verbose_name='標題',max_length=32) 增長: models.Department.objects.create(title='銷售部') models.Department.objects.create(**{'title':'銷售部'}) models.UserInfo.objects.create(name='劉也',depart=models.Department.objects.get(id=1)) models.UserInfo.objects.create(name='劉也',depart_id=1) obj = models.UserInfo.objects.filter(name='劉也').first() obj.roles.add([1,2,3]) 刪除: .delete() 修改: models.UserInfo.objects.filter(id__gt=5).update(name='xx') obj = models.UserInfo.objects.filter(name='劉也').first() obj.roles.set([2,3,6,7]) 查詢: models.UserInfo.objects.all() models.UserInfo.objects.values('id','name') models.UserInfo.objects.values_list('id','name') 經常使用操做: - 排序 - 連表 - filter篩選條件 __gt __gte __lt __contains __in ... 高級操做: F Q only # Queryset[obj,obj,obj] modes.UserInfo.objects.all().only('id','name') # select id,name from userinfo # Queryset[{},{},{}] modes.UserInfo.objects.all().values('id','name') # select id,name from userinfo # Queryset[(),(),()] modes.UserInfo.objects.all().values_list('id','name') # select id,name from userinfo 錯錯錯: result = modes.UserInfo.objects.all().only('id','name') for obj in result: print(obj.id,obj.name,obj.age) defer # Queryset[obj,obj,obj] modes.UserInfo.objects.all().defer('name') # select id,age from userinfo select_related 幫助開發者進行主動連表查詢。 # SELECT "app01_user"."id", "app01_user"."name", "app01_user"."depart_id" FROM "app01_user" result = models.User.objects.all() # SELECT "app01_user"."id", "app01_user"."name", "app01_user"."depart_id", "app01_department"."id", "app01_department"."title" FROM "app01_user" INNER JOIN "app01_department" ON ("app01_user"."depart_id" = "app01_department"."id") result = models.User.objects.all().select_related('depart') 注意:若是之後想要獲取部門名稱(跨表),必定要使用select_related進行主動跨表,這樣在最開始獲取數據時,將當前表和關聯表的全部數據都獲取到。 切記:錯錯錯 result = models.User.objects.all() for row in result: print(row.name,row.depart_id,row.depart.title) # row.depart.title就會讓性能大大下降 prefetch_related # 先執行SQL: select * from user where id<100 # 在執行SQL: select * from depart where id in [11,20] result = models.User.objects.filter(id__lt=100).prefetch_related('depart') 對比: 方式一: result = models.User.objects.all() # 1次單表 for row in result: print(row.id,row.name,row.depart.title) # 100次單表 方式二(小於4張表的連表操做): *** result = models.User.objects.all().select_related('depart') # 1次連表查詢 for row in result: print(row.id,row.name,row.depart.title) 方式三(大於4張表連表操做): # 先執行SQL: select * from user; # 在執行SQL: select * from depart where id in [11,20] result = models.User.objects.all().prefetch_related('depart') # 2次單表查詢 for row in result: print(row.id,row.name,row.depart.title) 執行原生SQL,場景:複雜SQL語句 from django.db import connection, connections # cursor = connections['db1'].cursor() cursor = connection.cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1,]) # row = cursor.fetchall() # 獲取符合條件的全部數據,models.User.objects.all() row = cursor.fetchone() # 獲取符合條件的第一條數據,models.User.objects.all().first() 全部ORM操做: ################################################################## # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # ################################################################## def all(self) # 獲取全部的數據對象 def filter(self, *args, **kwargs) # 條件查詢 # 條件能夠是:參數,字典,Q def exclude(self, *args, **kwargs) # 條件查詢 # 條件能夠是:參數,字典,Q def 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, IntegerField Article.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, Sum v = 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) > 1 def 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) # 構造額外的查詢條件或者映射,如:子查詢 UserInfo.objects.extra(where=['headline ? %s'], params=['Lennon']) # select * from userinfo where headline > 'Lennon' UserInfo.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) # select * from userinfo where (foo='a' OR bar = 'a') and baz = 'a' UserInfo.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) """ select id, name, (select col from sometable where othercol > 1) as new_id """ UserInfo.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中的設置) models.UserInfo.objects.filter(id=5).using('db1') ################################################## # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS # ################################################## def raw(self, raw_query, params=None, translations=None, using=None): # 執行原生SQL models.UserInfo.objects.raw('select * from userinfo where id > 10 ') # 若是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, connections cursor = 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 pytz import pytz pytz.all_timezones pytz.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, Sum result = 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) models.User.objects.filter(id__in=[11,21,31]) def delete(self): # 刪除 def update(self, **kwargs): # 更新 def exists(self): # 是否有結果 pass 3. Form、ModelForm、ModelFormSet (WTForms) 需求: 用戶輸入信息,獲取用戶輸入的信息。 示例:超市進銷存管理系統 Form & ModelForm ,本質幫助開發者對用戶請求中的數據進行格式校驗。 ModelFormSet ,本質幫助開發者對用戶請求中的數據進行批量格式校驗。 示例代碼見:源碼示例 贈送:單選下拉框變成radio框。
# 批量操做數據庫 for course_obj in course_obj_list: # 給當前課程 生成學生的學習記錄 stu_list = course_obj.re_class.customer_set.all().filter(status='studying') print(stu_list) studury_record_list = [] for stu_obj in stu_list: # models.StudyRecord.objects.create(student=stu_obj,course_record=course_obj) #普通的一個個添加 studury_record_list.append(models.StudyRecord(student=stu_obj, course_record=course_obj)) # 批量操做,一塊建立 models.StudyRecord.objects.bulk_create(studury_record_list, batch_size=3) if request.method == 'POST' and post_type == 'add': add_formset = AddFormSet(request.POST) if add_formset.is_valid(): permission_obj_list = [models.Permission(**i) for i in add_formset.cleaned_data] query_list = models.Permission.objects.bulk_create(permission_obj_list) # 建立成功後,在權限集合中加入新添加權限的別名 add_formset = AddFormSet() for i in query_list: permissions_name_set.add(i.name)