提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
Day 63 CVB 与模板层
Day63 CVB 与模板层
1. 内部如何实现?CBV源码剖析
url(r'^login/', views.MyLogin.as_view())
- 读源码,看到了@classonlymethod,所以as_view()是一个类方法
- as_view 是一个闭包函数,返回一个 view。会立刻变形成 views.view。
url(r'^login/', views.view) # FBV一模一样
- 所以两个本质上是一样的,都是路由对应函数内存地址。
- cls是我们自己写的类。
注意
- 不要自己去修改源码,除了bug没法找。
@classonlymethod
def as_view(cls, **initkwargs):
"""
Main entry point for a request-response process.
"""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
最后一步 return self.dispatch(request, *args, **kwargs)
注意
只要看到了 self.东西,一定要问自己,self是谁。
一定要时刻提醒自己,面向对象属性方法查找顺序。
- 先从对象自己找
- 再去类里面找
- 之后去爹中找。
dispatch方法是整个cbv的精髓所在。
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
- 获取请求的小写格式,然后在8个请求方法中,比对当前请求是否合法。
如果不再8个之中,就会报错。 - 如果有,getattr,反射,通过字符串来操作对象的属性或者方法。
这个handler变成了我们自己写的类里面的方法 - 自动调用get方法。
要求:
掌握到不看源码,也能够描述出cbv的内部执行流程。
2. 模板层
模板语法传值(locals方法,返回所有的名字)
def index(request):
# 模板语法可以传递的后端python数据类型
n = 123
f = 11.11
...
def func():
print('我被执行了')
return '你的另一半在等你'
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):
return '你到底会不会?'
obj=MyClass()
return render(request, 'index.html', locals())
总结:
-
《花括号》与《百分号》含义
- {{ }} 变量相关
- {% %} 逻辑相关
-
传递变量:
- { n }} 或 {{ f }} 或 {{ s }}
- 等等各种类型全部都可以传
-
传递函数
- {{ func }}
- 函数自动帮你加括号调用,传的是返回值。
- 切记,不支持给函数传参数,会给你报错。
-
传递类
-
类 {{ MyClass }}
-
对象 {{ obj }}
-
传类名的时候,也会自动加括号调用(实例化)
-
{{ obj.get_self }}
{{ obj.get_func }}
{{ obj.get_class }}
-
-
总结:
- 内部能够自动判断出当前的变量名是否可以加括号调用,
- 如果可以就自动执行(针对函数名和类名)
-
列表和字典取值
- 只能用句点符 . ,哪怕字典列表嵌套
- d.info.3.hobby
3. 模板语法过滤器
- 类似于一些简单的内置方法
- 后端传来一个变量,前端展示关于变量的信息
- Django内置 60+ 过滤器,我们了解10个左右,差不多了。
- 后面碰到了再去记忆
{{ 变量名|过滤器:'参数' }}
## 下面都可以包含在 <p></p> 标签中
--- --- --- --- ---
## 统计长度:
{{ s|length }}
## 默认值:
{{ b|default: '啥也不是' }}
## 文件大小(自动帮你和1024做计算。)
<!-- 后端 -->
file_size = 123421
<!-- 前端 -->
{{ file_size|filesizeformat }}
## 日期格式化
<!-- 后端 -->
import datetime
current_time = datetime.datetime.now()
<!-- 前端 -->
{{ current_time|date:'Y-m-d H:i:s' }}
## 切片操作:
{{ l|slice:'0:4:2' }}
## 切取字符(例如文章摘要,加上三个点):
info = 'aeioajflvnaowenvzbonod'
{{ info|truncatechars:9 }}
## 切取单词(不包含三个点了,只认空格):
egl = 'My name is jason, and my ...'
{{ egl|truncatedwords:9 }}
msg = 'I Love You and you?'
## 移除字符
{{ l|cut:' ' }}
## 拼接操作:
{{ l|join:'$' }}
## 拼接操作(加法):
{{ n|add:10 }}
## 拼接操作(加法):
{{ s|add:msg }}
## safe:取消转义
hhh = '<h1>敏敏</h1>'
不转义:{{ hhh }}
转义:{{ hhh|safe }}
后端转义
from django.utils.safestring import mark_safe
hhhh = '<h1>新新</h1>'
res = marksafe(hhhh)
以后你在写全栈项目的时候,前端代码也可以在后端写好,传递给前端。
4. 模板语法标签
一堆逻辑,包括for循环等等来展示变量
# 列表变量,在前端展示
def index(request):
l = ['小王', '小李', '敏敏', '帅帅', '张三', '月月', '静静', ]
return render(request, 'index.html', locals())
注意的关键字:
- endif / endfor
- forloop (for)
- empty (for)
- with 起别名
- 字典元素可以用句点符
for 循环
- 有 first,有last
{% for foo in l %}
<!-- <p>{{ forloop }}</p>-->
<p>{{ foo }}</p>
{% endfor %}
{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 7, 'revcounter0': 6, 'first': True, 'last': False}
if 判断
- 有elif,有else
{% if b %}
<p>baby</p>
{% elif s %}
<p>都来吧</p>
{% else %}
<p>老baby</p>
{% endif %}
混合使用
{% for foo in l %}
{% if forloop.first %}
<p>这是我的第一次</p>
{% elif forloop.last %}
<p>这是最后一次</p>
{% else %}
<p>{{ foo }}</p>
{% endif %}
{% empty %}
<p>都跑了</p>
{% endfor %}
字典方法都可以。
for foo in d.keys
for foo in d.values
for foo in d.items
起别名
- 解决:字典列表嵌套太多,名字太长
{{% with d.hobby.3.inf as nb %}}
<p>{ nb }</p>
{{% endwith %}}
5. 模板语法自定义过滤、标签、inclusion_tag
作用
- 局部页面
- 触发函数,把结果传到前端
必须要有的三个条件
- templatetags 文件夹
- 任意名称 py 文件
- 书写下面两句话
templatetags/mytag.py
# templatetags/mytag.py 必须包含两行代码
from django import template
register = template.Library()
# 自定义过滤器
@register.filter(name='baby')
def my_sum(v1, v2):
return v1 + v2
# 自定义标签
@register.simple_tag(name='plus')
def index(a, b, c, d):
return '%s-%s-%s-%s'%(a, b, c, d)
@register.inclusion_tag('left.html')
def left(n):
data = ['第{}项'.format(i) for i in range(n)]
# 第一种传值
# return {'data': data}
# 第二种传值,更方便
return locals()
index.html
<h1>自定义过滤器的使用(过滤器最多两个参数)</h1>
{% load mytag %}
花括号花括号
<p>{{ n|baby:666 }}</p>
<h1>自定义标签的使用</h1>
类似自定义函数
多个参数用空格隔开
花括号百分号
<p>{% plus 'jason' 123 123 123 %}</p>
<h1>自定义inclusion_tag</h1>
一般不是一个完整的页面,是一个局部页面
{% left 10 %}
left.html
<ul>
{% for foo in data %}
<li>{{ foo }}</li>
{% endfor %}
</ul>
6. 模板继承
一些网站,几乎不变,就是局部在跳转
步骤
- 先要划定被修改的区域
- 子板中继承,然后可以根据名字修改
- 除了自己写,也可以继承爹的模板:{{ block.super }} 名字
<div class="col-md-3">
<div class="list-group">
<a href="/app02/home/" class="list-group-item">首页</a>
<a href="/app02/login/" class="list-group-item">登录</a>
<a href="/app02/reg/" class="list-group-item">注册</a>
</div>
</div>
<!--...-->
{% block content %}
<h1>Hello world</h1>
Panel content
<div class="jumbotron">
<div class="container">
...
</div>
</div>
{% endblock %}
<!--...-->
lgoin.html
{% extends 'home.html' %}
{% block content %}
<h1 class="text-center">注册页面</h1>
<form action="" >
<p>username:</p>
<p>password:</p>
<input type="submit" class="btn btn-success" name="" id="">
</form>
{% endblock %}
一般来说,至少有三款会被修改的区域
- html
- css
- js
<!--css 区域-->
{% block css %}
<!--什么都不写 -->
{% endblock %}
<!--文本区域-->
{% block content %}
<!--什么都不写 -->
{% endblock %}
<!--js区域-->
{% block js %}
<!--什么都不写 -->
{% endblock %}
{% extends 'home.html' %}
{% block js %}
<!--写我单独的js -->
{% endblock %}
一般情况下,划定的区域越多,可扩展性越强
但是太多了,不如自己写。
模板语法导入
页面的某一个局部,当成模块的形式,哪里需要导哪里
<p>模板的导入</p>
{% include 'wasai.html' %}