视图层
视图函数必须有一个返回值,并且返回值的数据类型必须是HTTPresponse对象
HttpResponse
响应对象,响应可以使任何形式的内容,比如一个html文件的内容,一个重定向,一个404错误,一个xml文档,或者一张图片等。所以无论视图本身包含什么逻辑,都要返回响应。响应对象主要有三种形式:HTTPResponse、render、redirect
使用方式from django.shortcuts import HttpResponse,render,redirect
HttpResponse()
括号内直接跟一个具体的字符串作为响应体
render()
render(request,template_name[,context])
#参数:
#1、request:用于生成响应的请求对象,固定必须传入的第一个参数
#2、template_name:要是用的模板的完整名称,必须传入,render默认会去templates目录下查找模板文件
#3、context:可选参数,可以传入一个字典用来替换模板文件中的变量
综上,render的功能可以总结为:根据给定字典渲染模板文件,并返回一个渲染后的HttpResponse对象
redirect()
#返回重定向信息
def my_view(request):
...
return redirect('/some/url/')
#重定向的地址也可以是一个完整的URL
def my_view(request):
...
return redirect('http://www.baidu.com/')
JsonResponse
向前端返回一个json格式字符串
前后端分离
前后端数据交互的方式:通常情况下前后端数据交互采用的都是json的字符串(字典)
后端只需要写好相应的url,前端访问这个url
前后端序列化反序列化的方法
后端
json.dumps/json.loads
js前端
json.stringify/json.parse
向前端返回一个json格式字符串的两种方式
方式一
import json
def my_view(request):
data=['aaa','bbb']
return HttpResponse(json.dumps(data))
方式二
from django.http import JsonResponse
def my_view(request):
data=['aaa','bbb']
return JsonResponse(data,safe=False)
# 默认safa=True代表只能序列化字典对象,safe=False代表可以序列化字典以外的对象
FBV和CBV
django的视图层由这两种形式构成
- FBV基于函数的视图(Function base view)
- CBV基于类的视图(Class base view)
CBV
需要导入from django.views import view
创建的类必须继承view
CBV可以根据请求方法的不同,自动执行对应的方法
from django.views import View
class MyLogin(View):
def get(self,request):
print('我是MyLogin里面的get方法')
return render(request,'login.html')
def post(self,request):
print('我是MyLogin里面的post方法')
return HttpResponse('post')
URLS.PY的不同
#FBV 写法 路由>>视图函数内存地址
url(r'^index/',views.index)
#CBV写法
url(r'^login/',views.MyLogin.as_view())
#as_view 项目一启动,自动执行as_view方法
#CBV 在路由匹配上,本质还是FBV
采用CBV可以引入面向对象的思想对数据进行更高程度的封装
CBV源码
- dispatch函数中,利用反射去自己定义的类的对象中查找get属性或者是方法
getattr(obj,'get')
- 在对象中找不到就到类里面找
- 找到了就
return handler
调用get方法 - post相同
给CBV加装饰器
推荐使用内置模块
from django.utils.decorators import method_decorator
方法:
- 直接在函数名头上加(@装饰器名)(推荐写法:
method_decorator(装饰器名))
- 可以指定给谁装(
@method_decorator(装饰器名,name='被装饰函数名')
)
如果想在视图函数执行之前做一些操作,可以在CBV中定义dispatch方法来拦截
def dispatch(self,request,*args,**kwargs):
return super().dispatch(request,*args,**kwargs)
模板层
将Python嵌入到HTMl中
HTML代码+模板语法
def current_time(req):
# ================================原始的视图函数
# import datetime
# now=datetime.datetime.now()
# html="<html><body>现在时刻:<h1>%s.</h1></body></html>" %now
# return HttpResponse(html)
#另一种写法(推荐)
import datetime
now=datetime.datetime.now()
return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})
模板语法的两种书写格式
变量相关:{{ }}
逻辑相关:{% %}
模板传值
python基本数据类型全部支持传值
给HTML页面传递函数名的时候,模板语法会自动加括号调用该函数,并将函数的返回值当做展示依据,模板语法不支持函数传参
给HTML页面传类名的时候,模板语法也会自动加括号实例化产生对象。
总结:只要能加括号调用的,传递到html页面上都会自动加括号调用
过滤器
default
如果变量是false或者为空,则使用给定的默认值。
{{ value|default:'nothing'}}
length
返回值的长度,对字符串和列表都起作用
{{ value|length}}
如果value是[1,2,3,4]
,那么输出是4
filesizeformat
将值格式化成'人类可读的'文件尺寸。例如:
{{1024|filesizeformat}} 输出为1kb
date
如果value=datetime.datetime.now()
{{ value|date:"Y-m-d"}}
slice
切片
{{ name|slice:'0:3:3' }}
truncatechars
如果字符串多余指定字符数量,多余会被截断,替换成("...")结尾。
{{ value|truncatechars:9}}
safe
Django模板为了安全默认会对HTML标签和js等语法标签进行转义,有时候我们不希望这些元素被转义,可以通过设置过滤器。
script="'<script>alert(111)</script>"
{{ script|safe }}
注意:过滤器参数包含空格,必须用引号包起来
模板之标签
标签是为了在模板中完成一些特殊功能,语法为{%标签名%}
,一些标签还需要搭配结束标签{%endtag%}
常用标签
for标签
{% for person in person_list %}
<p>{{ person }}</p>
{% end for%}
#遍历每一个元素
Django为for标签内置了一些属性
forloop.counter:循环的当前索引值,从1开始计数;常用于生成一个表格或者列表的序号!
forloop.counter0:循环的当前索引值,从0开始计数;
forloop.revcounter: 循环结束的次数(从1开始)
forloop.revcounter0 循环结束的次数(从0开始)
forloop.first:判断当前是否循环的第一次,是的话,该变量的值为True。我们经常要为第一行加点特殊的对待,就用得上这个判断了,结合if。
forloop.last:如果这是最后一次循环,则为真
forloop.parentloop:对于嵌套循环,返回父循环所在的循环次数。某些场景下,这是个大杀器,能解决你很多头疼的问题。
for...empty
for标签带有一个可选的{% empty %}从句,在给出的组是空的或者没有被找到时执行的操作
if标签
{% if %}
会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
{% if num > 100 or num < 0 %}
<p>无效</p>
{% elif num > 80 and num < 100 %}
<p>优秀</p>
{% else %}
<p>凑活吧</p>
{% endif %}
注:在if标签中使用括号是错误的语法,这点不同于Python if语句支持 ,优先级可以使用if嵌套。if支持and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
with
使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
自定义标签和过滤器
通过python代码自定义标签和过滤器,然后使用{%load%}标签
必须要先有三步准备
-
在应用名下新建一个名字必须叫templatetags的文件夹
-
在该文件夹内新建一个任意名称的py文件
-
在该py文件中必须先写下两句代码
from django.template import Library
register=Library()
之后就可以用register来自定义过滤器和标签
使用自定义的过滤器
需要先再html页面上加载
-
自定义过滤器和默认的过滤器一样,最多只能接收两个参数
@register.filter(name='aaa') def index(a,b): return a+b #使用方式: {% load mytag %} {{ 1|aaa:1 }} {{ 1|aaa:100 }}
-
自定义标签,可以接收任意多个参数
@register.simple_tag(name='mytag') def mytag(a,b,c,d): return '%s?%s?%s?%s'%(a,b,c,d) #使用方法: #参数与参数之间必须用空格隔开 {% load mytag %} {% mytag 'a' 'b' 'c' 'd' %} {% load mytag %}
-
自定义inclusion_ tag
是一个函数 能够接受外界传入的参数 然后传递给一个html页面 页面上获取数据 渲染 完成之后 将渲染好的页面 放到调用inclusion_tag的地方 @register.inclusion_tag('mytag.html',name='xxx') def index(n): l=[] for i in range(n): l.append('第%s项'%i) return locals() # 将l直接传递给mytag.html页面 #使用方法: #当你需要使用一些页面组件的时候 并且该页面组件需要参数才能够正常渲染 你可以考虑使用inclusion_tag {% load mytag %} {% xxx 5 %}
注意:自定义的过滤器可以在逻辑语句使用 而自定义的标签不可以
模板的继承
需要事先在要使用的页面上划定区域,之后继承的时候就能使用这个区域
在页面上利用block划定想改的区域
{% block content%}
...
{% endblock %}
继承之后就可以通过名字找到对应的区域进行修改
{% extends 'home.html' %}
{% block content%}
修改模板中content区域内容
{% endblock %}
建议:一个模板页面至少有三块区域
1. css区域
2. html代码区域,可以设置多个block
3. js区域
{% extends 'home.html' %}
{% block css %}
<style>
p {
color: green;
}
</style>
{% endblock %}
{% block content %}
<p>login页面</p>
{% endblock %}
{% block js %}
<script>
alert('login')
</script>
{% endblock %}
{{block.super}}
:在子页面上继续沿用父页面的内容
模板的继承
- 在要继承的页面上通过block划定要改的区域
- 在子页面上继承extends
- 利用block,选择要修改的内容区域
模板的导入
将html页面当做木块直接导入
{% include 'xxx.html'}