render原理:
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)
一、视图层
视图函数必须返回一个HttpResponse对象。
视图函数可以是一个函数,也可以是一个类
FBV:基于函数的视图
CBV:基于类的视图
CBV
# 视图中语法 from django.views import View class MyLogin(View): def get(self,request): return render(request,'login.html') def post(self,request): return HttpResponse('我是类里面的post方法') # 路由中语法 url(r'^login/',views.MyLogin.as_view())
朝login提交get请求会自动执行MyLogin里面的get方法,而提交post请求也会自动执行MyLogin里面的post方法
为什么MyLogin针对不同的请求方法能够自动执行对应的方法?
可以查看as_view源码:
1.通过查看源码,我们得知 as_view是一个闭包类的绑定方法,返回一个view方法,调用views.MyLogin.as_view()方法等价于:views.view。再次去view源代码中去查看:
2.view方法中,首先会产生一个我们自己写的类即MyLogin的对象self,然后给这个对象的名称空间中添加request、位置参数、关键字参数属性,返回一个dispatch方法(我们自己创建的对象和类中没有,会去父类View中查询)
3.去父类中的dispatch方法查看,会判断request中返回的请求方式是否在八个基本请求方式中,如果在,则通过反射获取该请求方式的在我们的类中的方法,最后返回该方法的调用
django settings源码
1.在from django.conf import global_settings, settings,去settings中查看
2.再去LazySettings类中查看
3.再去类中的Settings查看
4.在Settings类中,我们可以发现里面有两个遍历的for循环,第一次是设置默认的全局的设置:global_settings,第二次是设置用户可以配置的设置:settings。用户配置了就用用户的,用户没有配就用默认的
二、模板层
1.模板语法符号
{{}} 变量相关
{%%} 逻辑相关
2.模板传值
Python基本数据数据类型全部支持传递给html文件
注意:传递函数和对象时候,会自动加括号,也就是传递时候会直接调用
对象:
后端给html文件传递数据有两种方式:
1.以一个字典方式,指名道姓传值
return render(request,'index.html',{'n':n,'f':f})
2.locals():将当前名称空间中所有的变量名全部传递给html页面
return render(request,'index.html',locals())
取值:django模板语法取值只有一种操作方式:句点符"."
.索引
.键
<p>{{ l.2 }}</p> # 索引 <p>{{ d.username }}</p> # 键 <p>{{ d.hobby.1.username.1 }}</p> # 索引和键混合
3.过滤器
|左边的会当做过滤器的第一个参数,过滤器名右边的会当做过滤器的第二个参数
|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>
补充:前后端取消转义
前端:|safe
后端:from django.utils.safestring import mark_safe
mark_safe('<h1>安全滴</h1>')
小结:前端代码不一定非要在前端页面写,可以在后端写好传递给前端页面使用,这样的话,你就可以利用到后端更加多的逻辑语法
4.标签
{% 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 %}
5.自定义
过滤器、标签、inclusion_tag可以自定义
前期步骤:
- 在应用名下新建一个名字必须叫templatetags文件夹
- 在该文件夹内新建一个任意名称的py文件(eg:mytag)
- 在该文件内 必须先写以下两句代码
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}
使用自定义时候,需要在html文件中导入mytag
{% load mytag %}
6.继承
某一个页面大部分区域都是公用的,那这个页面就可以作为模板页面
- 先在模板页面上通过block实现划定区域
{% block content %}
模板页面内容
{% endblock %}
- 子页面中先导入整个模板
{% extends '模板页面.html'%}
修改特定的区域 通过实现划定好的区域名称
{% block content %}
子页面内容
{% endblock %}
通常情况下,模板页面页面应该起码有三块区域
css、js、content
模板的block块越多,可扩展性越高
子页面调用父页面对应区域的内容,并且可以无限次调用
{{ block.super }}
7.导入
将html页面当做模块使用 哪里需要导哪里,这个html页面通常都不是完整的 只是一个局部样式
语法:
{% include 'left.html' %}
补充:基于django settings源码实现项目配置文件的,插拔式设计示例:
文件目录:
-mysetting
- conf
- settings.py
- lib
- conf
- __init__.py
- global_settings.py
start.py
import os import sys BASE_DIR = os.path.dirname(__file__) sys.path.append(BASE_DIR) if __name__ == '__main__': # 项目启动 就应该朝全局的大字典中设置键值对 os.environ['xxx'] = 'conf.settings' from lib.conf import settings print(settings.NAME)
NAME = '我是暴露给用户的配置文件'
NAME = '我是项目默认的配置文件'
import importlib import os from lib.conf import global_settings class Settings(object): def __init__(self): # 先循环遍历项目默认的全局配置文件 for name in dir(global_settings): # 判断变量名是否是大写 if name.isupper(): # 键值对设置给对象 k = name # NAME v = getattr(global_settings,name) # jason setattr(self,k,v) # 先获取暴露给用户的配置文件的字符串路径 module_path = os.environ.get('xxx') # conf.settings # 里面importlib模块 导入settings文件 md = importlib.import_module(module_path) # md = settings # 同上操作 for name in dir(md): # 判断变量名是否是大写 if name.isupper(): # 键值对设置给对象 k = name # NAME v = getattr(md,name) # jason setattr(self,k,v) settings = Settings()