render原理
from django.template import Context,Template def ab_render(request): temp = Template('<h1>{{ user_dict}}{{user_dict.username}}{{user_dict.password}}</h1>') # 相当于渲染页面 user_dict = Context({'user_dict':{'username':'jason','password':123}}) res = temp.render(user_dict) return HttpResponse(res)
视图函数并不一定就是函数 也可以是类
FBV:基于函数的视图(例如上面的ab_render方法)
CBV:基于类的视图
CBV基本写法
views.py
from django.views import View class MyLogin(View): def get(self,request): return render(request,'login.html') def post(self,request): return HttpResponse('我是类里的post方法')
urls.py
# CBV路由配置 url(r'^login/',views.MyLogin.as_view())
朝login提交get请求会自动执行MyLogin里面的get方法
而提交post请求也会自动执行MyLogin里面的post方法
为什么MyLogin针对不同的请求方法能够自动执行对应的方法
研究源码的突破口
url(r'^login/',views.MyLogin.as_view())
猜想
as_view要么是类里面定义的普通函数 @staticmethod
要么是类里面定义的绑定给类的方法 @classmethod
看源码发现是绑定给类的方法
# CBV路由配置 url(r'^login/',views.MyLogin.as_view()) # 等价于 # url(r'^login/',views.view) # FBV与CBV在路由匹配上本质是一样的 都是路由与函数内存地址的对应关系
Django setting源码
django暴露给用户一个可以自定义的配置
但是内部也有默认的配置
from django.conf import global_settings,settings # global_settings全局设定 setting用户设定 点击可以查看源码,完整设定
用户配置了就用用户的 用户没有配就用默认的
点开settings,内部为
settings = LazySettings() # 单例模式
os大字典在manage.py中一开始就赋(因为manage.py作为管理文件是项目一开始就运行的)
importlib方法:
b.py内容
name = 'jason'
a.py内容
# from conf import b # print(b.name) import importlib res = 'conf.b' md = importlib.import_module(res) # 把字符串转换为路径,导入 # 该方法最小单位是模块 不能是模块里面的名字 print(md.name) # jason
模板层
模板语法符号
{{}} 变量相关
{%%} 逻辑相关
注意: 下面是模板语法的注释 这个注释前端是看不见的。浏览器检查只能看到 <!----> 这类注释
{# ... #}
模板层之模板传值
python基本数据类型全部支持传递给html文件
对象
后端给html文件传递数据的两种方式
1.指名道姓
return render(request,'index.html',{'n':n,'f':f})
2.locals() # 会将当前名称空间中所有的变量名全部传递给html页面
return render(request,'index.html',locals())
html页面上 如何获取到后端传递过来的数据
{{ 变量名 }}
例:
def index(request): # python所有数据类型都支持传递给html页面 n = 11 f = 11.11 s = 'hello world' l = [1,2,3,4,5,6] d = {'username':'jason','password':123} t = (1,2,3,4,5,6,7) se = {1,2,3,4,5,6} b = True # return render(request,'index.html',{'n':n,'f':f}) 给模板传递数据 return render(request,'index.html',locals()) # 会将当前名称空间中所有的变量名全部传递给html页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <p>{{ n }}</p> {#模板语法的注释 这个注释前端是看不见的#} <!--浏览器检查能够看到--> <p>{{ f }}</p> <p>{{ s }}</p> <p>{{ l }}</p> <p>{{ d }}</p> <p>{{ t }}</p> <p>{{ se }}</p> </body> </html>
函数
注意:html中函数名会自动加括号执行 展示的是函数的返回值。并且模板语法不支持给函数传参
from django.shortcuts import render,HttpResponse,redirect
# Create your views here.
from django.template import Context,Template
def index(request):
def func():
print('func被执行了')
return 'from func'
# return render(request,'index.html',{'n':n,'f':f}) 给模板传递数据
return render(request,'index.html',locals()) # 会将当前名称空间中所有的变量名全部传递给html页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> {#<p>{{ n }}</p>#} {#模板语法的注释 这个注释前端是看不见的#} <!--浏览器检查能够看到--> <p>函数名会自动加括号执行 展示的是函数的返回值:{{ func }} 模板语法不支持给函数传参</p> </body> </html>
类
函数和对象会自动加括号
# 模板语法不支持传参
def index(request): # python所有数据类型都支持传递给html页面 class MyClass(object): def get_self(self): return 'from self' @staticmethod def get_func(): return 'from func' @classmethod def get_cls(cls): return 'from cls' obj = MyClass() # return render(request,'index.html',{'n':n,'f':f}) 给模板传递数据 return render(request,'index.html',locals()) # 会将当前名称空间中所有的变量名全部传递给html页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> {#<p>传类名 也会自动加括号实例化{{ MyClass }}</p>#} <p>{{ obj }}</p> <p>{{ obj.get_func }}</p> <p>{{ obj.get_self }}</p> <p>{{ obj.get_cls }}</p> </body> </html>
取值
django模板语法取值 只有一种操作方式 句点符 .
点索引
点键
<p>{{ l.2 }}</p> <p>{{ d.username }}</p> <p>{{ d.password }}</p> <p>{{ d.hobby.1.username.1 }}</p>
例:
def index(request):
# python所有数据类型都支持传递给html页面
n = 11
f = 11.11
s = 'hello world'
l = [1,2,3,4,5,6]
d = {'username':'jason','password':123,'hobby':['read',{'username':['jason','egon']}]}
t = (1,2,3,4,5,6,7)
se = {1,2,3,4,5,6}
b = True
# return render(request,'index.html',{'n':n,'f':f}) 给模板传递数据
return render(request,'index.html',locals()) # 会将当前名称空间中所有的变量名全部传递给html页面
<p>取值</p> <p>{{ l.2 }}</p> <p>{{ d.username }}</p> <p>{{ d.password }}</p> <p>{{ d.hobby.1.username.1 }}</p>
模板语法之过滤器 |
|length
|add
|default
|truncatechars
|truncatewords
|filesizeformat
|slice
|date
|safe
<p>过滤器 |左边的会当做过滤器的第一个参数 过滤器名右边的会当做过滤器的第二个参数</p> <p>求数据长度:{{ s|length }}</p> <p>加法运算:{{ n|add:10 }}、{{ s|add:13132 }}、{{ s|add:'DSB' }}</p> <p>默认值(判断值是否为空):{{ b|default:'这个b布尔值是True' }}、{{ ff|default:'这个ff布尔值是Flase' }}</p> <p>截取字符(截取5个字符 三个点也算):{{ s|truncatechars:8 }}</p> <p>截取单词(截取8个单词 三个点不算):{{ ss|truncatewords:8 }}、{{ sss|truncatewords:4 }}</p> <p>文件大小:{{ file_size|filesizeformat }}</p> <p>切片操作:{{ s|slice:'0:2' }}、{{ s|slice:"0:8:2" }}</p> <p>日期格式化:{{ ddd|date:'Y年/m月/d日' }}</p> <!--注意世界戳无法被时间格式化--> <p>转义:{{ res|safe }}、{{ res1 }}、后端直接标识安全:{{ res2 }}</p> <!--直接写res无法转义是因为计算机为了保证安全,不可随便转义-->
前后端取消转义
前端
|safe
后端
from django.utils.safestring import mark_safe # 先导入模块 mark_safe('<h1>安全滴</h1>')
总结:前端代码不一定非要在前端页面写,可以在后端写好传递给前端页面使用
这样的话 你就可以利用到后端更加多的逻辑语法
模板语法之标签 (逻辑相关)
查看内部fooloop变量内容
<p>标签</p> {% for foo in l %} <p>{{ forloop }}</p> {% endfor %}
{% for foo in l %} <!--l = [1,2,3,4,5,6]--> {% if forloop.first %} <p>这是我的第一次</p> {% elif forloop.last %} <p>这是最后一次了啊~</p> {% else %} <p>{{ foo }}</p> {% endif %} {% empty %} <p>for循环的对象内部没有值</p> {% endfor %}
注意:当一个值获取的步骤非常繁琐 但是又需要在很多地方用到 我们可以起别名来简化代码,别名只能在with内使用
<p>当一个值获取的步骤非常繁琐 但是又需要在很多地方用到 我们可以起别名来简化代码</p> {% with d.hobby.1.username.1 as eg %} {# 不需要加双括号 #} <p>别名只能在with内使用:{{ eg }}</p> <p>{{ d.hobby.1.username.1 }}</p> {% endwith %}
自定义过滤器 标签 inclusion_tag
先完成以下前期准备工作
1.在应用名下新建一个名字必须叫templatetags文件夹
2.在该文件夹内新建一个任意名称的py文件(eg:mytag)
3.在该文件内 必须先写以下两句代码
from django.template import Library register = Library()
# 自定义过滤器 @register.filter(name='my_sum') def index(a,b): return a + b # 自定义标签 @register.simple_tag(name='my_baby') def xxx(a,b,c,d): return '%s?%s?%s?%s'%(a,b,c,d) # 自定义inclusion_tag @register.inclusion_tag('demo.html',name='myin') def index1(n): l = [] for i in range(n): l.append(i) # 将列表传递给demo.html # return locals() return {'l':l}
<p>自定义的过滤器可以在逻辑语句中而自定义的标签不可以</p> {% if 10|my_sum:100 %} <p>条件成立</p> {% endif %} {% if my_baby 1 2 3 4 %} <p>条件成立</p> {% endif %} <p>自定义inclusion_tag的使用</p> {% load mytag %} {% myin 5 %} # 总结 页面上使用他们 统一先导入 {% load mytag %}
模板的继承
某一个页面大部分区域都是公用的 那这个页面就可以作为模板页面
当别人继承这个页面之后 如何修改对应的区域
先在模板页面上通过block实现划定区域
{% block content %}
模板页面内容
{% endblock %}
子页面中先导入整个模板
{% extends '模板页面.html'%}
修改特定的区域 通过实现划定好的区域名称
{% block content %}
子页面内容
{% endblock %}
通常情况下 模板页面页面应该起码有三块区域
{% block css %}
模板页面内容
{% endblock %}
{% block content %}
模板页面内容
{% endblock %}
{% block js %}
模板页面内容
{% endblock %}
# 模板的block块越多 可扩展性越高
支持子页面调用父页面对应区域的内容 并且可以无限次调用
{{ block.super }}
模板的导入
将html页面当做模块使用 哪里需要导哪里 这个html页面通常都不是完整的 只是一个局部样式
{% include 'left.html' %}
基于django settings源码实现项目配置文件的 插拔式设计