test测试是否符合条件返回trueorfalse
1.2exec的使用
exec从字符串中截取匹配的字符
1.3分组
-/g/m/i分组
JavaScript正则表达式-test测试是否符合条件返回trueorfalse-exec从字符串中截取匹配的字符
2.3注意submit与checkbook事件执行的先后顺序(绑定click事件)
submit动作执行先后checkbok的事件执行先后
实例;表单验证
实际就是别人写好了模板,样式,做个了结,在后面的项目部分,或使用这些个前端组件,进行快速的前端开发
几个比较出名的组件
easyuijqueryuibootstrap
组件的补充内容
3.1、响应式@media根据web界面的长框等因素使用不同的样式。即自适应3.2、字体图标以bootstrap为例,bootstrap在使用图标的时候应该注意到字体文件的导入。(之前博客的fontawesome图标不要导入字体)3.3、滚动图bxslider
importsocketserver=socket.socket()server.bind(('0.0.0.0',10086))server.listen(5)whileTrue:conn,add=server.accept()tmp_recv=conn.recv(1024)conn.send(b'HTTP/1.1200OK\r\n\r\n')conn.send('helloworld,你好世界'.encode('gbk'))#此处如果用utf-8那么浏览器会显示什么conn.close()-------------------print(tmp_recv)b'GET/HTTP/1.1\r\nHost:127.0.0.1:10086\r\nConnection:keep-alive\r\nPragma:no-cache\r\nCache-Control:no-cache\r\nUpgrade-Insecure-Requests:1\r\nUser-Agent:Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/69.0.3497.100Safari/537.36\r\nAccept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Language:zh-CN,zh;q=0.9\r\nCookie:csrftoken=VBVNk321AAGMuygu2OWoRXHUc2LiIspKoPaQfN1AbSY2WEUWPQS09ghoop1LzXFw;sessionid=os5tnm6lqwxxiill5py3ylzrbcs0j2hb\r\nAccept-Encoding:gzip,deflate\r\n\r\n'
我们可以使用decode对byte类型的数据进行加工。此处不做深入,上述过程只为了说明一点,web框架的本质就是byte类型的数据交互的过程。我们可以处理分析对方发过来的byte内容,然后处理后回复不通类型的数据
上面我们说到了web框架的本质,是处理b类型的数据和发送b类型的数据,在socket建立的情况下。
但是,此时我们需要明确,交互的数据有交互的规范。每种请求,不同状态码代表的含义,包头需要涵盖的内容等,这些东西我们都要去做处理分析。
这中间需要大量的人力投入,去开发一套稳定成熟的web框架。而此时,我们需要在web框架上搭建的网站,平台,系统等东西却还都没有开始开工。
现在市面上有大量成熟的web框架供我们去使用,这里就节省了我们去开发web框架和专门研究交互报文的复杂过程。更快的投入入高效的开发
2.1wsgivef.simple_server的使用
了解了HTTP协议和HTML文档,我们其实就明白了一个Web应用的本质就是:
如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。
正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。
这个接口就是WSGI:WebServerGatewayInterface。
使用wsgi相比于上面的直接建立socket,wsgi省去了建立socket监听端口这个过程
同时,为了规范代码我们可以将页面移动到view中,数据库操作移动到model中,url控制移动到controller中,
这样三个文件夹就组成了mvc架构
3、由wsgi模块引出的mvc架构与mtv架构
从上文我们知道
web框架本质->socket
wsgi->封装socket->是我们在编程时更专注于web,无需考虑socket,但是需要考虑返回值
wsgi中->规范三个文件夹model,view,controller组成mvc架构
同时,和mvc结构类似的有mtv架构实际model都是数据库操作,template中存放页面web,(类似于mvc中的v),view中存放url选路的操作(类似于mvc中的controller)
在python中又出现了再wsgi之上的封装的web框架
要注意WSGI/uwsgi/uWSGI这三个概念的区分。WSGI是一种通信协议。uwsgi是一种线路协议而不是通信协议,在此常用于在uWSGI服务器与其他网络服务器的数据通信。而uWSGI是实现了uwsgi和WSGI两种协议的Web服务器。
1.1命令行创建
我们在runserver的时候可以指定ip和端口号G:\mytest>pythonmanage.pyrunserver127.0.0.1:8888
1.2pycharm创建
1.3pycharm使用的一些注意点
新建django项目时报错
django1.x和django2.x的变化,实际变化不大。后面使用过程中会有深入理解
1.x的url与2.x的path及re_path
具体目录的功能会在下文实际应用过程中有更深刻的理解
app相当于一个大项目的小模块,一个大项目可以有多个模块组成,有不同的团队负责开发。将每个模块分别独立出来进行开发调试,能提高工作效率且便于项目的管理
3.1app的创建
F:\django_test>pythonmanage.pystartappCMDBF:\django_test>pythonmanage.pystartappopenstack3.2app的目录结构
3.3文件功能
典型的一个mvc架构
views用来对请求做处理,处理业务逻辑
templates用来存放web界面
4.1通过HttpResponse
f=open('templates\login.html','rb')data=f.read()returnHttpResponse(data)4.2通过renderrender的本质就是对HttpResponse的进一步封装
fromdjango.shortcutsimportrenderreturnrender(request,'login.html')4.3render的setting配置(目的告诉django你的templates在哪里)
TEMPLATES=[{'BACKEND':'django.template.backends.django.DjangoTemplates','DIRS':[os.path.join(BASE_DIR,'templates'),],#添加这一句'APP_DIRS':True,4.4redirect的本质
回复302的报文,并添加Location字段,ajax对此302的redirect不做反应
对于web中要使用的静态请求内容,一般不做views处理,将其配置成静态文件来处理。即访问这个url下的东西,直接是去获取文件。
6.1urls请求的解析
6.2views请求的处理、获取请求内包含的内容
deflogin(request):ifrequest.method=='POST':t_n=request.POST.get('name',None)t_p=request.POST.get('passwd',None)t_n=str(t_n)t_p=str(t_p)print(t_n)print(t_p)ift_n=='root'andt_p=='123':returnredirect('/home/')else:returnrender(request,'login.html',{'error_msg':'用户名或密码错误'})returnrender(request,'login.html')6.3模板语言使用渲染html文件并交给views返回
7.1收到请求
7.2路由系统urls解析发送过来的请求
7.3视图函数urls路由系统解析后,调用相应的视图函数对请求进行处理
7.4界面渲染调用配置文件或request请求的内容,或数据库内容,对web界面进行渲染,动态生成需要返回给用户的界面的过程
7.5返回用户
#注意以上的请求生存周期只是简单的概括,后续在中间件环境还会对生存周期做相应的扩展。
defhome(request):ifrequest.method=='POST':print('GET',request.GET)print('POST',request.POST)print('POSTLIST',request.POST.getlist('question1'))obj=request.POST.getlist('question1')foriinobj:print(i)returnrender(request,'home.html')ifrequest.method=='GET':print('GET',request.GET)print('POST',request.POST)returnrender(request,'home.html')GET
5.2获取文件名x.name
5.3循环接收文件chunks
defhome(request):ifrequest.method=='POST':tmp_file=request.FILES.get('test_paper')iftmp_file:f=open(tmp_file.name,'wb')foriintmp_file.chunks():f.write(i)f.close()foriinobj:print(i)returnrender(request,'home.html')6、CBV与FBV6.1FBVviews中定义一个函数来处理请求此处不做展开6.2CBVviews中定义一个类来处理请求6.3urls中的调用6.4class的定义继承View
deffunc(request):returnrender(request,"index.html",{'current_user':"aaaa"})---------------------------------------------------------------------
- {%forrowinuser_list%}{%ifrow=="alex"%}
- {{row}} {%endif%}{%endfor%}
1.1分组
urlpatterns=[re_path('newdetail-(\d+)-(\d+).html',views.newdetail)]
1.2分组并指定变量名
re_path('newdetail-(P
1.3view中接收参数的方式
defnewdetail(request,x1,x2):顺序接收defnewdetail(request,nid,nnid):按变量名接收defnewdetail(request,*args,**kwargs):多变量接收
2.1request.path_info
2.2urlname别名
2.2.1确定值
2.2.2搭配正则
{%url'tmp_name'123456%}2.3reverse此处不做描述,不常见,知道有这个方式即可
实际就是将总的项目文件夹中的urls拆分到各个app中的urls中
需要使用include
对象关系映射(英语:(ObjectRelationalMapping,简称ORM,或O/RM,或O/Rmapping)
1.1pythonmanage.pymakemigratations
1.2pythonmanage.pymigrate
直接执行上面两个指令,就能在项目的文件夹下发出现一个sqllite的文件,这就是django默认的数据库了
2.1setting中注册
DATABASES={'default':{'ENGINE':'django.db.backends.mysql','NAME':'django_1','HOST':'192.168.106.128','PORT':'3306','USER':'root','PASSWORD':'123456',}}2.2init中注册注意要先安装pymysql
3.1定义表
#在models中操作fromdjango.dbimportmodelsclassUser_info(models.Model):name=models.CharField(max_length=32)passwd=models.CharField(max_length=64)classxxx(models.Model):name=models.CharField(max_length=32)passwd=models.CharField(max_length=64)3.2注册表在setting中
INSTALLED_APPS=['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','app1',]3.3执行生成表
3.3.1pythonmanage.pymakemigratations
3.3.2pythonmanage.pymigrate
D:\untitled>pythonmanage.pymakemigrationsMigrationsfor'app1':app1\migrations\0001_initial.py-CreatemodelUser_info-CreatemodelxxxD:\untitled>pythonmanage.pymigrate4、单表的增删改查4.1增加
3种新增记录的方法->models.xxx.obj.create(k1=xxx,k2=xxx)->models.xxx.obj.create(**xxx_dict)->tmp_obj=models.xxx(k1=xxx,k2=xxx)tmp_obj.save()4.2查
4.2.1全查all()4.2.2过滤filter()过滤可以使用q语句,在后面的项目中会具体展开
4.2.5get没有该值会报错(可以用try捕捉异常)4.3删除deletemodels.User_info.objects.filter(name='xiaoming',passwd='aaaaaa').delete()4.4改updatemodels.User_info.objects.filter(id=4).update(name=444,passwd=444)4.5一个实例,用户信息管理
4.5.1Html补充Input的placeholder/a标签的text-decoration:none;/style="cursor:pointer"
5.1增加列(两个思路)
5.1.1给默认值
5.1.2留空
5.2删除列->直接删除
5.3修改->直接修改
5.4新建表
默认的自增id注意自增和主键的区别,设置primary_key后就不会出现默认的id了
5.5同步修改到数据库
pythonmanage.pymakemigrationspythonmanage.pymigrate七、django的中数据库的数据类型1、数据库中数据类型的分类1.1字符型
1.2数字
1.4布尔值0/1
有些数据类型和字段参数非数据库mysql本身的限制而是djangoadmin中的限制
2.1djangoadmin的使用(账号的建立)
要测试djangoadmin此处需要建立超级用户(venv)F:\django_test>pythonmanage.pycreatesuperuserUsername(leaveblanktouse'raytine'):rootEmailaddress:root@xxx.comPassword:Password(again):Thispasswordistooshort.Itmustcontainatleast8characters.Thispasswordistoocommon.Thispasswordisentirelynumeric.Bypasspasswordvalidationandcreateuseranyway[y/N]:ySuperusercreatedsuccessfully.(venv)F:\django_test>另外还需要将自建的数据表注册到djangoadmin中
fromCMDB.modelsimportUser_testadmin.site.register(User_test)2.2django中的数据类型
以下只列出几个常用的
Djangoadmin中会对一些charvarchar类型的字符做相应的限制如是否满足ipemail特征这些。
2.3.1nullnull=True是否为空
2.3.2Default默认值
2.3.3Primarykey主键
2.3.4db_column=’xxx’生成数据库表时列的名字
2.3.5db_index创建普通索引
2.3.6unique唯一索引
obj=models.User_test.objects.get(name='test_update')obj.name='new_one'obj.save()只能用get来修改才能生效2.3.10choice将一部分信息放在内存中属于django的操作
2.3.12Editable->djangoadmin中能否被编辑,如果设置了不能被编辑那么这个字段就从admin界面隐藏
2.3.13verbose_name->djangoadmin显示字段中文
2.3.14error_messages->错误信息
2.3.15help_text->djangoadmin提示
2.3.16validators->djangoform,自定义错误信息
dev_type=models.ForeignKey("devtype_table",to_field='tid',default=1,on_delete=models.2、外键字段再数据库中的保存形式fieldname_id我们在models中定义的字段名称,如果是foreignkey字段,在数据库中显示的字段名实际为fieldname_id,而直接的字段名,被用作表示对象
models.tb.object.create(name='root',user_group_id=1)4、一对多的情况下获取数据的三种方式4,1点获取
4.2values获取,此方法要配合双下划线一起使用
4.3values_list,此方法同样要配合双下划线一起使用
a.b_obj.filedname
value_list('b_obj__fieldname')
$.ajax({url:'/host',type:"POST",data:{'k1':123,'k2':"root"},success:function(data){console.log(data)}})2、ajax结合json的应用
classbook(models.Model):id=models.AutoField(primary_key=True)book_name=models.CharField(max_length=64)classauthor(models.Model):id=models.AutoField(primary_key=True)author_name=models.CharField(max_length=64)classcustom_book_and_author(models.Model):book_obj=models.ForeignKey(to='book',to_field='id',on_delete=models.CASCADE)author_obj=models.ForeignKey(to='author',to_field='id',on_delete=models.CASCADE)
此方法建立的多对多会自动生成第三张表,且我们无法通过程序直接操作第三张表,但是可以通过两个manytomany的对象来间接操作第三张表
classbook(models.Model):id=models.AutoField(primary_key=True)book_name=models.CharField(max_length=64)classauthor(models.Model):id=models.AutoField(primary_key=True)author_name=models.CharField(max_length=64)r=models.ManyToManyField('book')#自动创建3、增删改查的实现方式一,自定义关系表的情况下
可操作性空间大,但易用性比较麻烦
HostToApp.objects.create(hobj_id=1,aobj_id=2)方式二直接描述关系,间接操作第三张表,使用方便
data=JSON.parse(json_data);#如果没有指定dataTYPE而接收到的数据是json数据,则需要json.parse(data)来处理。如果指定里datatype为json那么,接收的data将被自动执行json.parse。相当于datatype封装了json.parse
$.ajax({url:'',type:'POST',data:'',dataType:'JSON',success:function(json_data){json_data['xxxx']}6.2traditions:true
假如接收到的数据中字典内嵌套了列表,那么ajax无法解析,需要添加traditions:true来支持
6.3serialize()
对于一个form,我们可以获取到form然后serialize()提交。简便操作
不难发现,我们不论获取什么信息如POST内容、GET内容、PATH路径等都是从request中获取,现有疑问,数据包交互的过程中,包头及包内还有很多其他的内容,我们如何去获取呢,能从request中去获取吗,有三个方法可以使用:request.environ/request.body/request.Meta
request.environ可以获取数据包内其他的信息,包括django不会去处理的信息
django不会去处理request对象中所有的信息,它只帮我们处理了一些较常用的POST、GET动作等,如果涉及到其他关于数据包的操作,如获取请求的UA时,我们就需要去request.environ中自己去获取了。
request.environ是一个字典,我们通过for的方式查看内部所有的值,此处不展开了
set_cookie是放置在请求头中的
response['k1']=v1
网页的标题、导航栏等结构,在多个页码都会显示,如果我们在写每个界面的时候重复写这些代码,效率很低。所以将重复代码做成模板,供其他页码调用
extends用于导入网页模板
{%extends'test.html'%}2、block的使用block用于定义代码块,即我们需要在模板中规划出相应的空白block,并给其命名,在调用模板的html文件中,我们需要定义出有内容的block块,页面在渲染过程中就会将这些block块替换到模板的block块位置。
需要注意普通内容的处理以及js、css内容的处理
导入模板{%extends'test.html'%}普通内容content{%blockcontent%}
对于一些很多页面都需要使用的小组件,我们可以将其单独写成一个html文件并使用include来调用{%include'tag.html'%}来使用
>base
base{%blockcontent%}{%endblock%}->main{%extends'xxx_base.html'%}{%blockcontent%}django中自带了一些filter处理前端的内容如
{{‘abc’|lower}}{{'
@register.simple_tag与load
->@register.simple_tag的使用{%mysimpleTagk1k2%}->思路a.app下创建templatetags目录b.创建任意.py文件c.创建template对象d.装饰器装饰函数@register.simple_tagdeffunc(a1,a2,a3....)return"asdfasd"e.settings中注册APPf.顶部{%loadxxoo%}g.{%函数名arg1arg2%}h.特殊情况TEMPLATES=[{'DIRS':[os.path.join(BASE_DIR,'templates'),],'libraries':{'local_simpletags':'table_admin.templatetags.local_simpletags',}},]缺点:不能作为if条件优点:参数任意->应用->直接输出返回结果->赋值给一个变量{%deal_strall_dict.oasx%}{%ifi==x%}2、自定义filter@register.filter与load
->filtera.app下创建templatetags目录b.任意xxoo.py文件c.创建template对象registerd.@register.filterdeffunc(a1,a2)return"asdfasd"e.settings中注册APPf.顶部{%loadxxoo%}g.{{参数1|函数名:"参数二,参数三"}}{{参数1|函数名:数字}}缺点:最多两个参数,不能加空格优点:能作为if条件十三、分页功能的实现1、阶段一原理1.1列表切片与queryset切片
x[0,10]x[11,20]x[21,30]1.2切片中变量的引入
x[y-1,y*10]1.3通过请求传入变量的方法
将y这个变量赋值定义为get内的一个参数xxx.com/y=12、阶段二基本功能实现2.1divmod的使用
->>>>divmod(10,2)(5,0)>>>divmod(10,6)(1,4)
2.2a标签生成连接
总页码数=divmod(k1,k2)[0]或divmod(k1,k2)[0]+1foriinrange生成"
{{html_str|safe}}-------------------------------fromdjango.utils.safestringimportmark_safetmpstr=make_safr(tmpstr)
3.1需要考虑的变量->列表数量变量->每页显示数量->一次显示多少页码->当前页->前一页、后一页->首页、尾页3.2需要考虑的情况->在页码充足的情况下的显示->接近首页->接近尾页->总页数少于一页锁展示的页码
2.1设置cookie
t_res=render(request,'paging.html',)t_res.set_cookie('per_page_num',123)returnt_res
2.2获取cookie
request.COOKIES.get('k1')request.COOKIES['k1']
4.1设置cookie
data.set_cookie('k',v)#关闭浏览器即失效4.2获取cookies(两种方式)
request.COOKIES.get('k1')request.COOKIES['k1']4.3cookies的两种时效设置
注意:和session对比,session的注销可以通过session.clear()来实现,但是cookie不行
7.1jquery与jquerycookie的应用
jquerycookie是一个依赖于jquery的插件,需要单独下载引入
添加location.reload(),使得配置的页面立即生效
7.3views函数返回
->获取当前页面request.GET.get('p')->获取cookies中每页显示的数目request.COOKIES.get()->分页函数处理->已选择的每页显示的select显示指定的option->$('select').val($.cookie('per_pagenum'))7.4完整代码
efis_it_auth(fun):definner(request,*args,**kwargs):t_u=request.COOKIES.get('user_auth')ift_u:t_result=fun(request)else:t_result=redirect('/lesson3/login')returnt_resultreturninner@is_it_authdefl3_index(request):t_u=request.COOKIES.get('user_auth')returnrender(request,'l3_index.html',{'user_name':t_u,'user_detail':user_data[t_u]})
9.2cbv的三种情况及需要使用的django装饰器
导入django装饰器->fromdjango.utils.decoratorsimportmethod_decorator9.2.1针对单个动作做认证,如get,自己定义的函数还要经过method_decorator处理
fromdjango.viewsimportViewfromdjango.utils.decoratorsimportmethod_decoratorclasstestcbv(View):@method_decorator(is_it_auth)defget(self,request):t_u=request.COOKIES.get('user_auth')returnrender(request,'l3_index.html',{'user_name':t_u,'user_detail':user_data[t_u]})defpost(self,request):pass9.2.2针对所有动作的操作
装饰dispatch函数
classtestcbv(View):@method_decorator(is_it_auth)defdispatch(self,request,*args,**kwargs):t_return=super(testcbv,self).dispatch(request,*args,**kwargs)#继承所有的方法returnt_return9.2.3针对类的装饰器
@method_decorator(is_it_auth,dispatch)classTheOBJ(View)十五、session1、cookie的缺点及注意事项不能包含敏感信息
3.1过程3.1.1生成随机字符串3.1.2将随机字符串返回给浏览器(通过cookie)3.1.3本地保存随机字符串(默认保存在数据库中)3.1.4给随机字符串管理相应的字典保存数据3.2操作django中将上述过程全部封装,只需要执行一步指令即可
request.session.get('key',none)#获取值request.session['key']#如果key不存在会报错5.2设置值
request.session.setdefault('key',value)#如果不存在,则设置,如果存在不改变request.session['key']=1235.3删除值
delrequest.session['key']5.4对字典的操作可以运用在request.session上
request.session.keys()request.session.values()request.session.items()5.5获取当前用户的随机字符串
request.sesson.session_key5.6删除脏数据
request.session.delete(request.session.session_key)request.session.clear()#和上面功能一样,但是不要去获取随机值5.8注销的实现
原理即通过request.session.clear()来清除session完成注销5.9注销实例代码
request.session.set_expiry(10)#单位是秒#这个值可以前端定义返回给后端5.12session的配置文件setting中配置
session可以通过配置保存在不同的地方->文件中->数据库中->cache缓存中->加密cookie中->数据库+缓存中(缓存没有命中,则保存到数据库)
总结就是一些涉及到钱的get或post动作,如果他人在第三方网站上嵌套了这类型的iframe,那么你带着你的cookie去访问,则你账户的钱就丢失了
简单的解决思路就是我给你一串随机字符串,你在发送交易动作的时候带上我给你的字符串,我知道是你主动访问的
{%csrf_token%}form中自动生成一个input框,将csrf_token随着post动作发送给对端
3.1只对此ajax生效的方法->设置X-CSRFtoken头部
$.ajax({url:''method:''data:{}headers:{'X-CSRFtoken':$.cookie('csrftoken')}success:function(data){}})3.2对于所有ajax请求批量生效的方法->xhr.setRequestHeader
#AJAX实例XHR请求XMLHttpRequest是AJAX的基础$.ajaxSetup({beforeSend:function(xhr,settings){xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));}});4、全局csrf与局部csrf全局:中间件django.middleware.csrf.CsrfViewMiddleware局部:●@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。●@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。注:fromdjango.views.decorators.csrfimportcsrf_exempt,csrf_protect
中间件的本质就是一个类,注册后的中间件,当请求来时会调用类中的方法在全局情况下对所有的请求和回复进行处理
->process_request(self,request)->process_view(self,request,callback,callback_args,callback_kwargs)->process_response(self,request,response)->process_exception(select,request,exception)->process_template_response3、定义中间件3.1定义类
fromdjango.utils.deprecationimportMiddlewareMixinclassM1(MiddlewareMixin)3.2注册中间件
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',]4、中间件中方法的理解4.1阶段一理解process_request(self,request)与process_response(self,request,response)
process_request(self,request)->请求到达服务端,request先过此方法->按中间件的注册顺序执行,即离views函数最远的先执行->如果无操作(无return),直接到达下一个中间件的process_request->如果有返回值->1.10以前版本给最靠近views的process_response做处理,依次返回->1.10之后版本交给自己的process_response处理后依次返回,不会到最贴近views的那个response了
process_response(self,request,response)->views函数处理完请求后,返回值会依次经过离views函数最近->离views函数最远->此方法需要return参数内的response或者自己定义的response
fromdjango.utils.deprecationimportMiddlewareMixinclassM1(MiddlewareMixin):defprocess_request(self,request):print('m1-request')defprocess_response(self,request,response):print('m1-response')returnresponseclassM2(MiddlewareMixin):defprocess_request(self,request):print('m2-request')defprocess_response(self,request,response):print('m2-response')returnresponseclassM3(MiddlewareMixin):defprocess_request(self,request):print('m3-request')defprocess_response(self,request,response):print('m3-response')returnresponse
4.2基于process_request实现黑名单阻塞
4.3阶段二理解process_view(self,request,callback,callback_args,callback_kwargs)->此阶段在画图的时候通常把它画在urls路由系统之前->但是从参数可以看出实际上在process_request的基础上,request.path_info内所带的一些参数已经被处理过->此方法和process_request一样,不需要有返回值return->如果有返回值,则讲给自己的response之后按response的顺序返回给客户端(与process_request返回值的现象是一致,包括版本)->此方法的执行顺序是按注册顺序执行,即离views函数最远的先执行
fromdjango.utils.deprecationimportMiddlewareMixinfromdjango.shortcutsimportHttpResponseclassM1(MiddlewareMixin):defprocess_request(self,request):print('m1-request')defprocess_response(self,request,response):print('m1-response')returnresponsedefprocess_view(self,request,callback,callback_args,callback_kwargs):print('m1_view')classM2(MiddlewareMixin):defprocess_request(self,request):print('m2-request')defprocess_response(self,request,response):print('m2-response')returnresponsedefprocess_view(self,request,callback,callback_args,callback_kwargs):print('m2_view')classM3(MiddlewareMixin):defprocess_request(self,request):print('m3-request')defprocess_view(self,request,callback,callback_args,callback_kwargs):print('m3_view')defprocess_response(self,request,response):print('m3-response')returnresponse
4.5阶段四理解process_template_response->运用场景少->process_template_response方法的执行取决于视图函数的返回的信息->视图函数如果使用render方法返回信息,中间件里的process_template_response方法就会被执行.
4.6概况有中间件的情况下的整个生命周期
请求->process_requess->process_views->urls路由->views模板渲染,数据库操作->process_template_response->process_exception->process_response
开发调试(实际就是什么地方都不放)内存文件数据库Memcache缓存(python-memcached模块)Memcache缓存(pylibmc模块)两个可以看做一个
将渲染好的html本地保存一份,之后浏览器发来的请求就直接回复保存的内容
缓存保存在文件中的配置CACHES={'default':{'BACKEND':'django.core.cache.backends.filebased.FileBasedCache','LOCATION':os.path.join(BASE_DIR,'local_cache'),}}4、如何使用缓存(3种类型)4.1单独视图函数加装饰器,整个界面做缓存
4.2对页面的某个部分做缓存
{%loadcache%}#和自定义的simpletag有点像{%cache5000k1%}5000即秒,k1为缓存的名称{%endcache%}实例
{%loadcache%}
{{t_time}}
{%cache5t_time%}{{t_time}}
{%endcache%}