django筆記

 

 

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)
相關文章
相關標籤/搜索