• django笔记


    1. 简述Http协议?
    	- 超文本传输协议
    		- 特点:
    			- 无状态,请求响应之后,再次发起请求时,不认识。
    			- 短连接,一次请求和一次响应就断开连接。
    		- 格式:
    		
    			- GET请求:输入地址回车:https://passport.jd.com/new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F
    				请求由两部分组成:请求头和请求体,请求头和请求体通过
    
    分割,请求头和请求头之间通过
    分割。
    					"""GET /new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F http1.1
    User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
    Host:jd.com
    
    """
    				响应由两部分组成:响应头和响应体,
    					b'HTTP/1.1 200 OK
    Date: Mon, 05 Nov 2018 01:15:31 GMT
    Server: Apache
    Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT
    ETag: "51-47cf7e6ee8400"
    Accept-Ranges: bytes
    Content-Length: 81
    Cache-Control: max-age=86400
    Expires: Tue, 06 Nov 2018 01:15:31 GMT
    Connection: Keep-Alive
    Content-Type: text/html
    
     <html><head> .... </html>'
    					
    			- POST请求:
    				请求由两部分组成:请求头和请求头
    					"""POST /new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F http1.1
    User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
    Host:jd.com
    
    username=haoxu666&password=123"""
    				响应:
    					b'HTTP/1.1 200 OK
    Date: Mon, 05 Nov 2018 01:15:31 GMT
    Server: Apache
    Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT
    ETag: "51-47cf7e6ee8400"
    Accept-Ranges: bytes
    Content-Length: 81
    Cache-Control: max-age=86400
    Expires: Tue, 06 Nov 2018 01:15:31 GMT
    Connection: Keep-Alive
    Content-Type: text/html
    
    用户名或密码错误'
    					
    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/ http1.1
    host:..
    Content-Type:application/x-www-form-urlencoded .....
    
    user=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/ http1.1
    host:..
    Content-Type:application/json .....
    
    {'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)
    

      

  • 相关阅读:
    ubuntu16.04下vim安装失败
    Sql Server函数全解(三)数据类型转换函数和文本图像函数
    Sql Server函数全解(二)数学函数
    Sql server 2008 中varbinary查询
    处理乱码问题
    快速排序
    《Java编程思想》笔记 第二章 一切都是对象
    1021: 组合数末尾的零
    11462
    The Bus Driver Problem
  • 原文地址:https://www.cnblogs.com/perfey/p/9917988.html
Copyright © 2020-2023  润新知