跳转底部

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)

  

posted on 2018-11-06 20:56  afly666  阅读(442)  评论(0编辑  收藏  举报

导航

回到顶部