Django-视图函数/模板渲染/过滤器
一、Django的视图函数
一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。
响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。
一个简单的视图
下面是一个以HTML文档的形式返回当前日期和时间的视图:
import datetime def login(request): now=datetime.datetime.now() html="<p>%s</p>"%now return HttpResponse(html)
def login(request): if request.method=="GET": return render(request,"login.html") else: user=request.POST.get("username") pwd=request.POST.get("password") print(user,pwd) if user=="chao" and pwd=="123": return render(request,"successfully.html") else: return HttpResponse("用户名密码错误")
二、FBV和CBV
FBV(function base views) 就是在视图里使用函数处理请求。
def login(request): if request.method=="GET": return render(request,"login.html") else: user=request.POST.get("username") pwd=request.POST.get("password") print(user,pwd) if user=="chao" and pwd=="123": return render(request,"successfully.html") else: return HttpResponse("用户名密码错误")
CBV(class base views) 就是在视图里使用类处理请求。
Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:
- 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
- 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
views视图函数:
from django.views import View class Myview(View): # get请求执行的函数 def get(self,request): return render(request,"login.html") # post请求执行的函数 def post(self,request): user = request.POST.get("username") pwd=request.POST.get("password") print(user,pwd) if user=="chao" and pwd=="123": return render(request,"successfully.html") else: return HttpResponse("用户名密码错误")
每条请求过来自动去执行对应的函数,什么请求就执行什么函数的逻辑
urls搜索路径:
from app01.views import Myview urlpatterns = [ url(r'^$',Myview.as_view()), url(r'^login/',Myview.as_view()), ]
添加类的属性可以通过两种方法设置,第一种是常见的Python的方法,可以被子类覆盖。
from django.http import HttpResponse from django.views import View class GreetingView(View): name = "yuan" def get(self, request): return HttpResponse(self.name) # You can override that in a subclass class MorningGreetingView(GreetingView): name= "alex"
第二种方法,你也可以在url中指定类的属性:
在url中设置类的属性Python
from app01.views import Myview urlpatterns = [ url(r'^$',Myview.as_view(name="zzz")), # 指定name属性值 url(r'^login/',Myview.as_view()), ]
from django.views import View class Myview(View): name="chao" # 原属性值 # get请求执行的函数 def get(self,request): return HttpResponse(self.name)
上面的name="zzz"会把类中原有的属性值给覆盖掉; 类里面必须有name属性,并且会被传进来的这个属性值给覆盖掉
三、给视图加装饰器
使用装饰器装饰FBV
FBV本身就是一个函数,所以和给普通的函数加装饰器无差:
def wrapper(login): def inner(request,*args,**kwargs): print("执行前") ret = login(request) # login需要request这个参数,必须传 print("执行后") return ret return inner @wrapper def login(request): if request.method=="GET": return render(request,"login.html") else: user=request.POST.get("username") pwd=request.POST.get("password") print(user,pwd) if user=="chao" and pwd=="123": return render(request,"successfully.html") else: return HttpResponse("用户名密码错误")
若想单独给post请求添加功能则需要将post请求单独封装成函数然后加上装饰器;
使用装饰器装饰CBV
类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其转换为方法装饰器。
Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器。
1、直接给对应的HTTP请求方法添加装饰器
def wrapper(login): def inner(request,*args,**kwargs): print("执行前") ret = login(request) print("执行后") return ret return inner from django.views import View from django.utils.decorators import method_decorator class Myview(View): # get请求执行的函数 @method_decorator(wrapper) def get(self,request): return render(request,"login.html") @method_decorator(wrapper) # post请求执行的函数 def post(self,request): user = request.POST.get("username") pwd=request.POST.get("password") print(user,pwd) if user=="chao" and pwd=="123": return render(request,"successfully.html") else: return HttpResponse("用户名密码错误")
使用CBV时要注意,请求过来后会先执行dispatch()这个方法,dispatch负责HTTP请求方法对应请求方法的分发;
我们可以在dispatch分发前后添加相应的功能;
from django.views import View class Myview(View): def dispatch(self, request, *args, **kwargs): print("分发前") ret=super().dispatch(request, *args, **kwargs) print("分发后") return ret # get请求执行的函数 def get(self,request): return render(request,"login.html") # post请求执行的函数 def post(self,request): user = request.POST.get("username") pwd=request.POST.get("password") if user=="chao" and pwd=="123": return render(request,"successfully.html") else: return HttpResponse("用户名密码错误")
2、给dispatch添加装饰器就是给所有的Http请求添加了装饰器
def wrapper(login): def inner(request,*args,**kwargs): print("装饰器执行前") ret = login(request) print("装饰器执行后") return ret return inner from django.views import View from django.utils.decorators import method_decorator class Myview(View): @method_decorator(wrapper) def dispatch(self, request, *args, **kwargs): ret=super().dispatch(request, *args, **kwargs) return ret # get请求执行的函数 def get(self,request): return render(request,"login.html") # post请求执行的函数 def post(self,request): user = request.POST.get("username") pwd=request.POST.get("password") if user=="chao" and pwd=="123": return render(request,"successfully.html") else: return HttpResponse("用户名密码错误")
3、给类添加装饰器用name属性指定给哪个HTTP请求方法添加装饰器
def wrapper(login): def inner(request,*args,**kwargs): print("装饰器执行前") ret = login(request) print("装饰器执行后") return ret return inner from django.views import View from django.utils.decorators import method_decorator @method_decorator(wrapper,name="get") class Myview(View): def dispatch(self, request, *args, **kwargs): ret=super().dispatch(request, *args, **kwargs) return ret # get请求执行的函数 def get(self,request): return render(request,"login.html") # post请求执行的函数 def post(self,request): user = request.POST.get("username") pwd=request.POST.get("password") if user=="chao" and pwd=="123": return render(request,"successfully.html") else: return HttpResponse("用户名密码错误")
四、request对象
当一个页面被请求时,Django就会创建一个包含本次请求原信息(请求报文中的请求行、首部信息、内容主体等)的HttpRequest对象。
Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。
请求相关的常用值
- path_info 返回用户访问url,不包括域名
- method 请求中使用的HTTP方法的字符串表示,全大写表示。
- GET 包含所有HTTP GET参数的类字典对象
- POST 包含所有HTTP POST参数的类字典对象
- body 请求体,byte类型 request.POST的数据就是从body里面提取到的
- META 获取请求头的元信息
例如:
使用方法:
def index(request): print(request.method) #请求方式 print(request.path) #请求路径,不带参数的 print(request.POST) #post请求数据 字典格式 print(request.GET) #get的请求数据 字典格式 print(request.META) #请求头信息,将来用到哪个咱们再说哪个 print(request.get_full_path()) #获取请求路径带参数的,/index/?a=1 print(request.is_ajax()) #判断是不是ajax发送的请求,True和False
五、response对象
与由Django自动创建的HttpRequest对象相比,HttpResponse对象是我们的职责范围了。我们写的每个视图都需要实例化,填充和返回一个HttpResponse。
HttpResponse类位于django.http模块中。
1、HttpResponse
import datetime def login(request): if request.method=="GET": now = datetime.datetime.now() return HttpResponse(now)
2、render
import datetime def login(request): if request.method=="GET": now = datetime.datetime.now() return render(request,"login.html",{"name":now})
3、redirect
给浏览器发送了一个重定向的请求,浏览器拿到你要重定向的url,然后自动发送了一个ip+端口+路径/login/,的一个请求,后端在配置对应的url('^login/',views.login)
import datetime from django.shortcuts import redirect def login(request): if request.method=="GET": now = datetime.datetime.now() return render(request,"login.html",{"name":now}) else: user=request.POST.get("username") pwd=request.POST.get("password") print(request.path_info) if user=="chao" and pwd=="123": return redirect("/login/") # 重定向到登录页面 else: return HttpResponse("用户名密码错误")
点击登录按钮密码验证通过直接被重定向,路径还是登录页面;
六、摸板渲染
变量:
{{ 变量 }}
import datetime def login(request): if request.method=="GET": now = datetime.datetime.now() return render(request,"login.html",{"name":now}) # 字典的形式传参替换相应的内容
实际上做的就是字符串替换,如果传的是对象可以通过点的方式取到对应的值
逻辑:
{% 逻辑 %}
七、过滤器
在Django的模板语言中,通过使用 过滤器 来改变变量的显示。
过滤器的语法: {{ value|filter_name:参数 }}
使用管道符"|"来应用过滤器。
例如:{{ name|lower }}会将name变量应用lower过滤器之后再显示它的值。lower在这里的作用是将文本全都变成小写。
注意事项:
- 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
- 过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
- 过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
- '|'左右没有空格没有空格没有空格
Django的模板语言中提供了大约六十个内置过滤器。
示例:
def login(request): return render(request,"login.html",{"name":"123123123123123"})
<body> {{ name|filesizeformat }} </body>
default
如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值。
{{ value|default:"nothing"}}
如果value没有传值或者值为空的话就显示nothing
length
返回值的长度,作用于字符串和列表。
{{ value|length }}
返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.
filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB'
, '4.1 MB'
, '102 bytes'
, 等等)。例如:
{{ value|filesizeformat }}
如果 value 是 123456789,输出将会是 117.7 MB。
slice
切片,如果 value="hello world",还有其他可切片的数据类型
{{value|slice:"2:-1"}}
date
格式化,如果 value=datetime.datetime.now()
{{ value|date:"Y-m-d H:i:s"}}
truncatechars
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
参数:截断的字符数
{{ value|truncatechars:9}} #注意:最后那三个省略号也是9个字符里面的,也就是这个9截断出来的是6个字符+3个省略号,有人会说,怎么展开啊,配合前端的点击事件就行啦
truncatewords
在一定数量的字后截断字符串,是截多少个单词。
例如:‘hello girl hi baby yue ma’,
{{ value|truncatewords:3}} #上面例子得到的结果是 'hello girl h1...'
cut
移除value中所有的与给出的变量相同的字符串
{{ value|cut:' ' }}
如果value为'i love you',那么将输出'iloveyou'.
join
使用字符串连接列表,{{ list|join:', ' }},就像Python的str.join(list)
timesince(了解)
将日期格式设为自该日期起的时间(例如,“4天,6小时”)。
采用一个可选参数,它是一个包含用作比较点的日期的变量(不带参数,比较点为现在)。 例如,如果blog_date是表示2006年6月1日午夜的日期实例,并且comment_date是2006年6月1日08:00的日期实例,则以下将返回“8小时”:
{{ blog_date|timesince:comment_date }}
分钟是所使用的最小单位,对于相对于比较点的未来的任何日期,将返回“0分钟”。
timeuntil(了解)
似于timesince,除了它测量从现在开始直到给定日期或日期时间的时间。 例如,如果今天是2006年6月1日,而conference_date是保留2006年6月29日的日期实例,则{{ conference_date | timeuntil }}将返回“4周”。
使用可选参数,它是一个包含用作比较点的日期(而不是现在)的变量。 如果from_date包含2006年6月22日,则以下内容将返回“1周”:
{{ conference_date|timeuntil:from_date }}
重点记:
safe
Django的模板中在进行模板渲染的时候会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全,django担心这是用户添加的数据,比如如果有人给你评论的时候写了一段js代码,这个评论一提交,js代码就执行啦,这样你是不是可以搞一些坏事儿了,写个弹窗的死循环,那浏览器还能用吗,是不是会一直弹窗啊,这叫做xss攻击,所以浏览器不让你这么搞,给你转义了。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。
def login(request): if request.method=="GET": return render(request,"login.html",{"name":"<a href='#'>点我</a>"})
<body>
{{ name }}
</body>
关闭HTML的自动转义:
<body> {{ name|safe }} </body>