day63——CBV内部原理、过滤器、标签、inclusion_tag、模版的继承
CBV源码解析
CBV路由函数用的是类,但其实CBV和FBV在路由匹配上本质是一样的,都是路由对应函数的内存地址。
url(r'^login/',views.MyLogin.as_view())
"""
通过看as_view的函数的源码我们得知,as_view函数是绑定给类( 被@classonlymethod修饰)的方法,它里面包了一个view函数,类调用as_view方法执行会返回一个view函数的内存地址,而view函数只有在前面路由匹配成功的时候才会执行,所以上面视图可以变形为:"""
url(r'^login/',views.view) # 和CBV的原理一样。
as_view内部主要源码
def as_view(cls,**initkwargs): # cls就是我们自己写的类 MyCBV
...
def view(request,*args,**kwargs):
self=cls(**initkwargs) # cls 也是我们自己的的类,调用类实例化产生self对象。
...
"""
view函数在路由匹配成功后执行,返回dispatch函数的执行结果,
而dispatch函数才是CBV原理所在。"""
return self.dispatch(request,*args,**kwargs)
...
return view # as_view执行返回view函数内存地址
# CBV的精髓
def dispatch(self,request,*args,**kwargs):
# 获取当前请求的小写格式,然后对比当前请求方式是否合法(是否在http_method_names列表内)
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
"""
反射:通过字符串来操作对象的属性或者方法
handler = getattr(自己写的类产生的对象,'get',当找不到get属性或者方法的时候就会用第三个参数)
handler = 我们自己写的类里面的get方法"""
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) # 自动调用get方法
ps:
-
函数名/方法名,加括号执行的优先级最高
-
对象属性的查找属性复习:
先充对象自己找,再去产生对象的类里面找,之后去父类里面找
-
看源码时看到
slef.xxx
,一定要搞清楚当前这个self到底指代的是谁。
模版语法传值
{{ xxx }}
:与变量相关(int,float){% xxx %}
:与逻辑相关(for,if)
路由层urls.py
url(r'^index',views.index),
视图层views.py
def index(request):
# 模版语法可以传递的后端python数据类型
int_1 = 123
float_1 = 11.1
str_1 = 'How are you?'
bool_1 = True
list_1 = ['aaa', 'bbb', 'ccc']
tuple_1 = (111, 222, 333)
dict_1 = {'name': 'tom', 'age': '18'}
set_1 = {'AAA', 'BBB', 'CCC'}
dict_list_1={'list_2':[111,{'hobby':'read'}]}
def func():
print('我被执行了')
return '函数func的返回值'
class MyClass(object):
def get_self(self):
return self
@staticmethod
def get_func():
return 'func'
@classmethod
def get_class(cls):
return 'cls'
def __str__(self): # 对象被展示到html页面上 就类似于执行了打印操作也会触发__str__方法
return '我被打印了'
obj_1 = MyClass()
return render(request, 'index.html', locals())
模版层index.html页面
<body>
<p>{{ int_1 }}</p>
<p>{{ float_1 }}</p>
<p>{{ str_1 }}</p>
<p>{{ list_1 }}</p>
<p>{{ bool_1 }}</p>
<p>{{ tuple_1 }}</p>
<p>{{ dict_1 }}</p>
<p>{{ set_1 }}</p>
<p>django模版语法的取值 是固定的格式 只能采用“句点符”;即可以点键也可以点索引 还可以两者混用</p>
<P>{{ dict_list_1.list_2.1.hobby }}</P>
<p>传递函数名会自动加括号调用 但是模版语法不支持给函数传额外的参数:{{ func }}</p>
<p>传类名的时候也会自动加括号调用(实例化){{ MyClass }}</p>
<p>内部能够自动判断出当前的变量名是否可以加括号调用 如果可以就会自动执行针对的是函数名和类名</p>
<p>{{ obj_1 }}</p>
<p>{{ MyClass.get_class }}</p>
<p>{{ MyClass.get_self }}</p>
<p>{{ MyClass.get_func }}</p>
<p>{{ obj_1.get.self }}</p>
<p>{{ obj_1.get_func }}</p>
</body>
浏览器渲染
过滤器
过滤器就类似于模版语法自带的内置方法,由于django的内置过滤器有60多个, 我们不需要学这么多,我们先学习常用。
基本语法:
{{ 数据|过滤器:参数 }}
视图层
def index(request):
# 模版语法可以传递的后端python数据类型
import datetime
from django.utils.safestring import mark_safe
int_1 = 123
str_1 = 'How are you?'
bool_1 = True
bool_2 = False
list_1 = ['aaa', 'bbb', 'ccc']
file_size =111111
current_time = datetime.datetime.now()
str_2="""One should not pry into the faults of others,
into things done and left undone by others.
One should rather consider what by oneself is done and left undone."""
info ="""盼望着,盼望着,东风来了,春天的脚步近了。
一切都像刚睡醒的样子,欣欣然张开了眼。山朗润起来了,水涨起来了,太阳的脸红起来了。"""
msg =" H o w A r e Y o u"
label_1="<h1>标签一</h1>"
label_2="<script>alert('你好呀!')</script>"
label_3 = mark_safe('<h1>安全的</h1>') # 后端转义
return render(request, 'index.html', locals())
模版层index.html页面
<h1>过滤器:</h1>
<p>统计长度:{{ str_1|length }}</p>
<p>默认值(第一个参数布尔值是True就展示第一个参数的值否在展示冒号后面的值):</p>
<p>{{ bool_1|default:'啥也不是' }}</p>
<p>{{ bool_2|default:'啥也不是' }}</p>
<p>文件大小:{{ file_size|filesizeformat }}</p>
<p>日期格式化:{{ current_time|date:'Y-m-d H:i:s' }}</p>
<p>切片操作(支持步长):{{ list_1|slice:'::2' }}</p>
<p>切取字符(包含三个点):{{ info|truncatechars:9 }}</p>
<p>切去单词(不包含三个点,按空格切):{{ str_2|truncatewords:9 }}</p>
<p>切去单词(不包含三个点,按空格切):{{ info|truncatewords:9 }}</p>
<p>移除特定的字符:{{ msg|cut:' ' }}</p>
<p>拼接操作(加法):{{list_1|join:'$'}}</p>
<p>拼接操作(加法):{{ int_1|add:10 }}</p>
<p>拼接操作(加法):{{ str_1|add:str_2 }}</p>
<p>默认不转义,加safe表示数据是安全的,转义数据类容</p>
<p>转义:{{ label_1|safe }}</p>
<p>转义:{{ label_2|safe }}</p>
<p>转义:{{ label_3 }}</p>
<p></p>
浏览器渲染 :
标签
# for循环
{% for foo in l %}
<p>{{ forloop }}</p>
<p>{{ foo }}</p> 一个个元素
{% endfor %}
"""
{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 6, 'revcounter0': 5, 'first': True, 'last': False}"""
# if判断
{% if b %}
<p>那个谁</p>
{% elif s%}
<p>你好</p>
{% else %}
<p>再见</p>
{% endif %}
# for与if混合使用
{% for foo in lll %}
{% if forloop.first %}
<p>第一个</p>
{% elif forloop.last %}
<p>最后一个/p>
{% else %}
<p>{{ foo }}</p>
{% endif %}
{% empty %}
<p>for循环的可迭代对象内部没有元素 根本没法循环</p>
{% endfor %}
# 处理字典其他方法
{% for foo in d %}
<p>{{ foo }}</p>
{% endfor %}
{% for foo in d.keys %}
<p>{{ foo }}</p>
{% endfor %}
{% for foo in d.values %}
<p>{{ foo }}</p>
{% endfor %}
{% for foo in d.items %}
<p>{{ foo }}</p>
{% endfor %}
# with起别名
{% with d.hobby.3.info as read %}
<p>{{ read }}</p>
在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
<p>{{ d.hobby.3.info }}</p>
{% endwith %}
自定义过滤器、标签、inclusion_tag
定义前的三步准备工作
-
在应用下创建一个文件名必须叫
templatetags
文件夹 -
然后在该文件夹下创建任意名称的py文件,eg:mytag.py
-
在该py文件内必须先书写下面两句代码(每个单词都必须相同)
from django import template register=template.Library
自定义过滤器
# 定义
@register.filter(name='sum_filter') # 可以取任意的名字,用的时候对应好即可
def my _sum(v1,v2) # 自定义过滤器最多可以有两个参数
return v1 + v2
# 使用
{% load mytag %} # 先加载py文件
<p>{{ n|sum_filter:666 }}
自定义标签
# 定义
@register.simple_tag(name='str_format') # 可以取任意的名字,用的时候对应好即可
def my_format(a,b,c,d) # 可以有多个参数,类似于自定义函数
return '%s-%s-%s-%s'%(a,b,c,d)
# 使用
# 标签的多个参数需要用空格彼此隔开
{% load mytag %} # 先加载py文件
<p>{% plus 'tom' 111 'aaa' 222%}</p>
自定义inclusion_tag
内部原理:
先定义一个方法,在页面上调用该方法(可以传值),该方法会生成一些数据然后传递给html页面,之后将渲染好的结果放到调用的位置
# 定义
@register.inclusion_tag('left_menu.html')
def left(m):
data = ['第{}项'.format(i) for i in range(n)]
# return {'data':data}
return locals()
# left.html内容
"""
<ul>
{% for foo in data %}
<li>{{ foo }}</li>
{% endfor %}
</ul>"""
# 使用
{% left 5 %} # 写到其他页面调用的位置
应用场景:
当html页面某一个地方的页面需要传参才能动态的渲染出来,并且在多个页面上都需要使用该局部,那么就可以考虑将该局部页面做成inclustion_tag的形式。
模版的继承
不知道你有没有见过一些网站 ,这些网站页面整体都不怎么变化, 只是某一些局部在做变化,这就是运用到模版继承的原理。模版页面创建好后,子页面只需要继承该模版不用写任何内容子页面就能到达跟模版页面一样的效果,在模版页面划分好区域,子页面继承版本页面之后还可以对这些划分的区域进行局部的修改,实现整体不变,而局部变化的效果。
-
创建模版页面,并划分可变的区域
# home.html """ 模版内容 {% block content %} 模版内容 {% endblock %} 模版内容 """
-
子页面继承模版页面home.html
# login.html {% extends 'home.html' %} # 声明继承哪个模版 # 继承了之后子页面跟模版页面长的是一模一样的,并在划分的区域进行修改 """ {% block content %} 子页面内容 {% endblock %} """
模版页面应有的三个可变区域
-
css区域:用于修改子页面的样式
""" {% block css %} 页面样式 {% endblock %} """
-
js区域:给子页面增加的动态效果
""" {% block js %} <script>...</script> {% endblock %} """
-
content区域:改变部分内容
""" {% block content %} 子页面内容 {% endblock %} """
模版的导入
将常用的局部页面做成模块的形式,哪个地方需要就可以直接导入使用即可。
{% include 'wasai.html' %}