目录
一、CBV源码解析
# 在urls中CBV是这么写的
url(r'^myclass',views.Myclass.as_view())
#myclass是我们自己写的类,继承了View,这里类调用as_view这个方法,先要判断这个方法是什么方法
'''
在源码中可以看到
@classonlymethod
def as_view(cls, **initkwargs):
这说明我们找的这个函数,它是类的绑定方法,先会把我们自定义的类当做第一个参数传入
然后我们可以看到这个as_view的返回值是view函数,我们在去看view是什么
'''
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# cls 是我们自己定义的类
if hasattr(self, 'get') and not hasattr(self, 'head'):
# 对类的一些属性进行赋值
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 这里又看到一个新的函数dispatch,点击跳转
return self.dispatch(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
# 判断这个请求是不是在http_method_names中,往上翻可以看到http_method_names是一个存放请求名字的列表,不过都是小写的
if request.method.lower() in self.http_method_names:
# 这里写了一个getattr用字符串来操作对象的属性或方法
# handler = getattr(自己写的类产生的对象,'get',当找不到get属性或者方法的时候就会用第三个参数),显然,我们在定义自己的类的时候,就要求要写对应的get请求方法和post请求方法,此处的代码让我们可以直接调用对应的请求方法,无需判断
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
二、模版语法
1 传值
{{}}:变量相关
{% %}:逻辑相关
def index(request):
# 模版语法可以传递的后端python数据类型
n = 123
f = 11.11
s = '我也想奔现'
b = True
l = ['小红','姗姗','花花','茹茹']
t = (111,222,333,444)
d = {'username':'jason','age':18,'info':'这个人有点意思'}
se = {'晶晶','洋洋','嘤嘤'}
# 以上所有的数据类型都可以直接展示到页面上
def func():
return 'Nihao'
# 函数在模版语言中不能加括号,也是写名字,显示的是返回值
class MyClass():
def get_self(self):
return 'self'
@staticmethod
def get_func():
return 'func'
@classmethod
def get_class(cls):
return 'cls'
obj = MyClass()
# 模版语言会自动判断这个名字能不能加()调用,如果可以的话,返回调用结果的返回值,此处类的调用返回的是实例化对象的内存地址
# 也可以通过类或者对象访问内部的方法,得到的也都是返回值
# 模版语言的取值用的是‘句点符’
{{d.username}} # 字典.key
{{l.0}} # 列表.索引
# 也可以连着点,只要不违反规范,此处即使点不到也不会报错
<p>{{ n }}</p>
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ b }}</p>
<p>{{ l }}</p>
<p>{{ d }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
<p>传递函数名会自动加括号调用 但是模版语法不支持给函数传额外的参数:{{ func }}</p>
<p>传类名的时候也会自动加括号调用(实例化){{ MyClass }}</p>
<p>内部能够自动判断出当前的变量名是否可以加括号调用 如果可以就会自动执行 针对的是函数名和类名</p>
<p>{{ obj }}</p>
<p>{{ obj.get_self }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_class }}</p>
2 过滤器(最多只能传两个参数)
过滤器就想当于模版语法内置的 内置方法
django内置有60多个过滤器,这里只了解10个左右
# 基本语法
{{数据|过滤器:参数}}
# 特殊:转义
# 后端
from django.utils.safestring import mark_safe
res = mark_safe('<h1>aaa</h1>')
# 此处的res传给前端的时候,由于考虑到安全性,需要我们写safe参数,但是我们已经在后端通过安全的方法创建,所以不用写
# 前端
{{res}} #
<p>统计长度:{{ s|length }}</p>
# s ='abc' 结果:3
<p>默认值(第一个参数布尔值是True就展示第一个参数的值否在展示冒号后面的值):{{ b|default:'啥也不是' }}</p>
# b = None 结果:啥也不是
<p>文件大小:{{ file_size|filesizeformat }}</p>
# file_size = 1024 结果:1kb 默认以一个字节为单位,传数字
<p>日期格式化:{{ current_time|date:'Y-m-d H:i:s' }}</p>
# current_time = datetime.datetime.now()
# 结果:2020-05-28 17:25:47 和现在时间不同是settins时区不同
<p>切片操作(支持步长):{{ l|slice:'0:4:2' }}</p>
# l = [1,2,3,4,5,6,7] 结果:[1,3] 此处后面的传值和python切片传值相同
<p>切取字符(包含三个点):{{ info|truncatechars:9 }}</p>
# word = '阿斯达撒大所多撒大大大所' 结果:阿斯...
<p>切取单词(不包含三个点 按照空格切):{{ egl|truncatewords:9 }}</p>
# egl='my name is jason my age is 18 and i am from China'
# 结果:my name is jason my age is 18 and ...
<p>切取单词(不包含三个点 按照空格切):{{ info|truncatewords:9 }}</p>
# 如上
<p>移除特定的字符:{{ msg|cut:' ' }}</p>
<p>拼接操作:{{ l|join:'$' }}</p> # 列表中的字符串拼接
<p>拼接操作(加法):{{ n|add:10 }}</p> # add前后数字的加减
<p>拼接操作(加法):{{ s|add:msg }}</p> # 字符串拼接
<p>转义:{{ hhh|safe }}</p>
<p>转义:{{ sss|safe }}</p>
<p>转义:{{ res }}</p>
3 标签
# for循环
{% for foo in l %}
<p>{{ forloop }}</p> # 每个元素的一些属性,比如first,last,是否是第一个元素,是否是最后一个元素等等
#{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 9, 'revcounter0': 8, 'first': True, 'last': False}
<p>{{ foo }}</p> # 一个个元素
{% endfor %}
# if判断,和python没区别
{% if b %}
<p>baby</p>
{% elif s%}
<p>都来把</p>
{% else %}
<p>老baby</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.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 nb %}
<p>{{ nb }}</p>
在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
<p>{{ d.hobby.3.info }}</p>
{% endwith %}
4 自定义过滤器,标签,inclusion_tag
必须要做的三件事
- 在应用下创建一个名字”必须“叫templatetags文件夹
- 在该文件夹内创建“任意”名称的py文件 eg:mytag.py
- 在该py文件内"必须"先书写下面两句话(单词一个都不能错)
from django import template
register = template.Library()
4.1 自定义过滤器
@register.filter(name='baby') # 注册一个过滤器,写上过滤器的名字
def my_sum(v1, v2): # 最多传两个值
return v1 + v2 # 展示在前端的是返回值
# 使用
{% load mytag %}
<p>{{ n|baby:666 }}</p>
4.2 自定义标签(可以传多个参数)
@register.simple_tag(name='plus') # 类似于自定义函数
def index(a,b,c,d):
return '%s-%s-%s-%s'%(a,b,c,d)
# 使用
# 标签多个参数彼此之间空格隔开
<p>{% plus 'jason' 123 123 123 %}</p>
4.3 自定义inclusion_tag
# 这里的html是我们要提前在这个页面上渲染好的html文件,相当与一个中转站
@register.inclusion_tag('left_menu.html')
def left(n):
data = ['第{}项'.format(i) for i in range(n)]
# 第一种
# return {'data':data} # 将data传递给left_menu.html
# 第二种
return locals() # 将data传递给left_menu.html
# 在我们想书写自定义标签的页面书写
{% left 5 %}
# 总结:当某个页面布局被多个页面使用,且这个布局需要传参才能实现,我们可以用这个形式
5 模版的继承
存在有一些页面,它们的布局都一模一样,用户请求后,改变的只是一部分内容,这些页面就用到了模版的继承。
'''
首先要有一个主页,这个主页代码是完整的,我们为主页划分一下
导航栏,body左,body右,页脚
我们要求每次请求值修改body右的页面内容,就要在body右整体代码外加
{% block content %}
body右内容
{% endblock %}
此时这一块代码相当于被解封了,其他继承了主页的页面都可以修改这一块的内容变成自己的页面
'''
'''
注册页面的布局和主页完全一样,就是要在body右修改成提交表单的形式
'''
# 先要继承
{% extends 'home.html' %}
# 继承之前要把这个页面代码清空,此时两个页面的内容是完全相同的
# 注册页面如果要把自己的代码替换到可修改的地方,就需要划分自己的代码
{% block content %}
注册页自己的内容,去替换被解封的主页区域,形成自己的页面
{% endblock %}
# 通常我们的模版有三块可以被修改的地方,css代码,html代码,js代码
{% block css %}
{% endblock %}
{% block content %}
{% endblock %}
{% block js %}
{% endblock %}
# 每个子页面也可以有自己独有的css代码 html代码 js代码
6 模块的导入
# 在一个html页面把内容清空,只写需要被导入的代码
# 在其他需要用到这个页面的代码的地方导入即可
{% include 'wasai.html' %}